1. ホーム
  2. android

[解決済み] Androidでの全文検索例

2023-03-16 20:49:37

質問

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

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

SQLiteデータベースのテーブル(名前は example_table ) には 4 つのカラムがあります。しかし、1つのカラム(名前は text_column という名前の列) だけです。のすべての行は text_column の各行は、0 から 1000 ワードまでの様々なテキストを含んでいます。行の総数は 10,000 を超えています。

  • テーブルおよび/または FTS 仮想テーブルをどのように設定しますか。
  • どのようにFTSクエリを実行しますか? text_column ?

追加メモです。

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

どのように解決するのですか?

最も基本的な答え

私はすべてができるだけ明確で読みやすいように、以下のプレーンなSQLを使用しています。あなたのプロジェクトでは、Androidの便利なメソッドを使用することができます。その db オブジェクトのインスタンスです。 SQLiteDatabase .

FTSテーブルの作成

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

これは onCreate() メソッドに記述することができます。 SQLiteOpenHelper クラスのメソッドを追加します。

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.')");

を使うのがよいでしょう。 SQLiteDatabase#insert あるいは 準備された文 よりも execSQL .

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 テーブルはインデックスを含みますが、通常のテーブルからの実際のデータは含まれません。その代わり、通常のテーブルのコンテンツへのリンクがあります。これは 外部コンテンツテーブル .

テーブルの作成

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クエリを行おうとすると fts_example_table に対して今FTSクエリを実行しようとしても、結果は得られないでしょう。その理由は、一方のテーブルを変更しても、もう一方のテーブルが自動的に変更されないからです。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')");

で、テーブル全体を再構築します。しかし、これは時間がかかるので、小さな変更のたびに実行するものではありません。外部コンテンツテーブルへのすべての挿入が終了した後に行うことになります。データベースを自動的に同期させる必要がある場合は、次のようにします。 トリガー . ここに移動 をクリックし、少し下にスクロールすると案内が表示されます。

データベースを問い合わせる

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

これは前と同じです。ただし、今回は text_column (そして docid ). 外部コンテンツテーブルの他のカラムからデータを取得する必要がある場合はどうすればよいでしょうか。そのため docid はFTSテーブルの 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仮想テーブルの他の使用方法を見るために、これらのドキュメントをよく読んでください。

追加メモ