[解決済み] Androidでの全文検索例
質問
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
.
db.execSQL("CREATE VIRTUAL TABLE fts_table USING fts3 ( col_1, col_2, text_column )");
これは
onCreate()
メソッドに記述することができます。
SQLiteOpenHelper
クラスのメソッドを追加します。
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
.
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仮想テーブルの他の使用方法を見るために、これらのドキュメントをよく読んでください。
- SQLite FTS3 と FTS4 の拡張機能 (SQLite ドキュメント)
- データの保存と検索 (Android docs)
追加メモ
関連
-
[解決済み] Androidのソフトキーボードをプログラムで閉じる/隠すにはどうすればよいですか?
-
[解決済み] SQLiteのINSERT/per-secondのパフォーマンスを向上させる
-
[解決済み] Androidでアクティビティ起動時にEditTextにフォーカスが当たらないようにする方法
-
[解決済み] Vim 直前の検索ハイライトをクリアする
-
[解決済み] Androidの「コンテキスト」とは何ですか?
-
[解決済み] MySQLのDESCRIBE [table]に相当するSQLiteはありますか?
-
[解決済み】Android UserManager.isUserAGoat()の正しい使用例?)
-
[解決済み】全文検索エンジンの比較 - Lucene、Sphinx、Postgresql、MySQL?
-
[解決済み] AndroidにおけるViewPager2の適切な実装
-
[解決済み] Android - タイトルバーに戻るボタンが表示される
最新
-
nginxです。[emerg] 0.0.0.0:80 への bind() に失敗しました (98: アドレスは既に使用中です)
-
htmlページでギリシャ文字を使うには
-
ピュアhtml+cssでの要素読み込み効果
-
純粋なhtml + cssで五輪を実現するサンプルコード
-
ナビゲーションバー・ドロップダウンメニューのHTML+CSSサンプルコード
-
タイピング効果を実現するピュアhtml+css
-
htmlの選択ボックスのプレースホルダー作成に関する質問
-
html css3 伸縮しない 画像表示効果
-
トップナビゲーションバーメニュー作成用HTML+CSS
-
html+css 実装 サイバーパンク風ボタン
おすすめ
-
[解決済み] Android Webview - キャッシュを完全に削除する
-
[解決済み] HttpPostによる画像送信
-
[解決済み] handler.postDelayed()を停止する。
-
[解決済み] Android StudioからADBを手動で再起動する方法
-
[解決済み] AndroidでTextViewの下にアンダーラインを引くには
-
[解決済み] EditTextの右側のDrawableにonClickListenerを設定する [重複] [重複
-
[解決済み] LayoutParamsの高さを密度に依存しないピクセル数でプログラム的に設定する。
-
[解決済み] ViewPager2でスワイプを無効にするには?
-
[解決済み] WhatsAppでメッセージを送信する
-
[解決済み] AndroidでSQliteのプリペアドステートメントを使用するにはどうすればよいですか?