web-dev-qa-db-ja.com

Androidの全文検索の例

Androidで全文検索(FTS)を使用する方法を理解するのに苦労しています。 FTS3およびFTS4拡張機能に関するSQLiteドキュメント を読みました。そして、私は Android上で行うことが可能です を知っています。しかし、理解できる例を見つけるのに苦労しています。

基本的なデータベースモデル

SQLiteデータベーステーブル(名前はexample_table)には4つの列があります。ただし、全文検索のためにインデックスを作成する必要がある列は1つだけです(名前はtext_column)。 text_columnのすべての行には、長さが0〜1000ワードのテキストが含まれています。行の総数は10,000を超えています。

  • テーブルやFTS仮想テーブルをどのように設定しますか?
  • text_columnでFTSクエリをどのように実行しますか?

追記:

  • 1列のみにインデックスを付ける必要があるため、FTSテーブルの使用(およびexample_tableの削除)のみ 非FTSクエリでは非効率 になります。
  • このような大きなテーブルでは、text_columnの重複エントリをFTSテーブルに格納することは望ましくありません。 この投稿外部コンテンツテーブル の使用を提案します。
  • 外部コンテンツテーブルはFTS4を使用しますが、FTS4は Android AP​​I 11以前ではサポートされていません です。回答ではAPI> = 11を想定できますが、下位バージョンをサポートするためのオプションについてコメントすることは役立ちます。
  • 元のテーブルのデータを変更しても、FTSテーブルは自動的に更新されません(逆も同様)。この基本的な例では、回答に triggers を含める必要はありませんが、それでも役立ちます。
85
Suragch

最も基本的な答え

すべてが可能な限り明確で読みやすいように、以下のプレーンなSQLを使用しています。プロジェクトでは、Android簡易メソッドを使用できます。以下で使用されるdbオブジェクトは、 SQLiteDatabase のインスタンスです。

FTSテーブルの作成

db.execSQL("CREATE VIRTUAL TABLE fts_table USING fts3 ( col_1, col_2, text_column )");

これは、拡張SQLiteOpenHelperクラスのonCreate()メソッドに入れることができます。

FTSテーブルに入力

db.execSQL("INSERT INTO fts_table VALUES ('3', 'Apple', 'Hello. How are you?')");
db.execSQL("INSERT INTO fts_table VALUES ('24', 'car', 'Fine. Thank you.')");
db.execSQL("INSERT INTO fts_table VALUES ('13', 'book', 'This is an example.')");

execSQLよりも SQLiteDatabase#insert または prepared statement を使用することをお勧めします。

クエリFTSテーブル

String[] selectionArgs = { searchString };
Cursor cursor = db.rawQuery("SELECT * FROM fts_table WHERE fts_table MATCH ?", selectionArgs);

SQLiteDatabase#query メソッドを使用することもできます。 MATCHキーワードに注意してください。

より充実した回答

上記の仮想FTSテーブルには問題があります。すべての列にインデックスが作成されますが、一部の列にインデックスを作成する必要がない場合、これはスペースとリソースの無駄です。 FTSインデックスが必要な列は、おそらくtext_columnだけです。

この問題を解決するために、通常のテーブルと仮想FTSテーブルの組み合わせを使用します。 FTSテーブルにはインデックスが含まれますが、通常のテーブルの実際のデータは含まれません。代わりに、通常のテーブルのコンテンツへのリンクがあります。これは 外部コンテンツテーブル と呼ばれます。

enter image description here

テーブルの作成

db.execSQL("CREATE TABLE example_table (_id INTEGER PRIMARY KEY, col_1 INTEGER, col_2 TEXT, text_column TEXT)");
db.execSQL("CREATE VIRTUAL TABLE fts_example_table USING fts4 (content='example_table', text_column)");

FTS3ではなくFTS4を使用する必要があることに注意してください。 FTS4は、APIバージョン11より前のAndroidではサポートされていません。(1)API> = 11の検索機能のみを提供するか、(2)FTS3テーブルを使用できます(ただし、データベースが大きくなります)両方のデータベースにフルテキスト列が存在するためです)。

テーブルに入力します

db.execSQL("INSERT INTO example_table (col_1, col_2, text_column) VALUES ('3', 'Apple', 'Hello. How are you?')");
db.execSQL("INSERT INTO example_table (col_1, col_2, text_column) VALUES ('24', 'car', 'Fine. Thank you.')");
db.execSQL("INSERT INTO example_table (col_1, col_2, text_column) VALUES ('13', 'book', 'This is an example.')");

(繰り返しますが、挿入にはexecSQLよりも良い方法があります。読みやすくするために使用しています。)

fts_example_tableでFTSクエリを実行しようとした場合、結果は得られません。その理由は、1つのテーブルを変更しても、他のテーブルは自動的に変更されないためです。 FTSテーブルを手動で更新する必要があります。

db.execSQL("INSERT INTO fts_example_table (docid, text_column) SELECT _id, text_column FROM example_table");

docidは、通常のテーブルのrowidのようなものです。)外部コンテンツテーブルに変更(INSERT、DELETE、UPDATE)を行うたびに、FTSテーブルを更新する(インデックスを更新できるようにする)必要があります。 。これは面倒です。事前に作成されたデータベースのみを作成している場合は、次のことができます

db.execSQL("INSERT INTO fts_example_table(fts_example_table) VALUES('rebuild')");

テーブル全体が再構築されます。ただし、これは遅くなる可能性があるため、少し変更するたびにやりたいことではありません。外部コンテンツテーブルへのすべての挿入が完了したら、それを行います。データベースの同期を自動的に維持する必要がある場合は、 triggers を使用できます。 ここに行き 、少し下にスクロールして道順を見つけます。

データベースのクエリ

String[] selectionArgs = { searchString };
Cursor cursor = db.rawQuery("SELECT * FROM fts_example_table WHERE fts_example_table MATCH ?", selectionArgs);

これは以前と同じですが、今回はtext_column(およびdocid)のみにアクセスできます。外部コンテンツテーブルの他の列からデータを取得する必要がある場合はどうなりますか? FTSテーブルのdocidは外部コンテンツテーブルのrowid(この場合は_id)と一致するため、結合を使用できます。 ( この回答 に感謝します)

String sql = "SELECT * FROM example_table WHERE _id IN " +
        "(SELECT docid FROM fts_example_table WHERE fts_example_table MATCH ?)";
String[] selectionArgs = { searchString };
Cursor cursor = db.rawQuery(sql, selectionArgs);

参考文献

これらのドキュメントを注意深く読んで、FTS仮想テーブルを使用する他の方法を確認してください。

その他の注意事項

  • SQLite FTSクエリのセット演算子(AND、OR、NOT)には、 Standard Query Syntax および Enhanced Query Syntax があります。残念ながら、Androidは明らかに拡張クエリ構文をサポートしていません( hereherehere 、および here )。つまり、ANDとORの混合が困難になることを意味します( UNION の使用または PRAGMA compile_options の使用が必要です) 。とても残念です。この領域に更新がある場合は、コメントを追加してください。
111
Suragch

からのコンテンツを使用してftsテーブルを再構築することを忘れないでください。

更新、挿入、削除のトリガーでこれを行います

3
James Kipling