Pertanyaan Contoh pencarian teks lengkap di Android


Saya mengalami kesulitan memahami cara menggunakan pencarian teks lengkap (FTS) dengan Android. Saya sudah membaca Dokumentasi SQLite pada ekstensi FTS3 dan FTS4. Dan saya tahu itu mungkin dilakukan di Android. Namun, saya mengalami kesulitan menemukan contoh yang dapat saya pahami.

Model basis data dasar

Tabel database SQLite (bernama example_table) memiliki 4 kolom. Namun, hanya ada satu kolom (bernama text_column) yang perlu diindeks untuk pencarian teks lengkap. Setiap baris text_column berisi teks dengan panjang bervariasi dari 0 hingga 1000 kata. Jumlah baris lebih dari 10.000.

  • Bagaimana Anda mengatur tabel dan / atau tabel virtual FTS?
  • Bagaimana Anda melakukan kueri FTS text_column?

Catatan tambahan:

  • Karena hanya satu kolom yang perlu diindeks, hanya menggunakan tabel FTS (dan turun example_table) akan menjadi tidak efisien untuk kueri non-FTS.
  • Untuk meja besar seperti itu, menyimpan entri duplikat dari text_column dalam tabel FTS tidak diinginkan. Posting ini menyarankan menggunakan tabel konten eksternal.
  • Tabel konten eksternal menggunakan FTS4, tetapi FTS4 adalah tidak didukung sebelum Android API 11. Jawaban dapat mengasumsikan API> = 11, tetapi mengomentari opsi untuk mendukung versi yang lebih rendah akan sangat membantu.
  • Mengubah data dalam tabel asli tidak secara otomatis memperbarui tabel FTS (dan sebaliknya). Termasuk pemicu dalam jawaban Anda tidak diperlukan untuk contoh dasar ini, tetapi akan tetap membantu.

75
2018-04-23 06:18


asal


Jawaban:


Jawaban Paling Dasar

Saya menggunakan sql sederhana di bawah ini sehingga semuanya sejelas dan dapat dibaca sebaik mungkin. Dalam proyek Anda, Anda dapat menggunakan metode kenyamanan Android. Itu db objek yang digunakan di bawah ini adalah turunan dari SQLiteDatabase.

Buat Tabel FTS

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

Ini bisa masuk ke dalam onCreate() metode perpanjangan Anda SQLiteOpenHelper kelas.

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

Akan lebih baik untuk digunakan SQLiteDatabase # insert atau pernyataan siap dari execSQL.

Tabel FTS Permintaan

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

Anda juga bisa menggunakan SQLiteDatabase # query metode. Perhatikan MATCH kata kunci.

Jawaban Lengkap

Tabel FTS virtual di atas memiliki masalah dengan itu. Setiap kolom diindeks, tetapi ini adalah pemborosan ruang dan sumber daya jika beberapa kolom tidak perlu diindeks. Satu-satunya kolom yang membutuhkan indeks FTS mungkin adalah text_column.

Untuk mengatasi masalah ini kita akan menggunakan kombinasi tabel biasa dan tabel FTS virtual. Tabel FTS akan berisi indeks tetapi tidak ada data aktual dari tabel biasa. Sebaliknya ia akan memiliki tautan ke isi dari tabel biasa. Ini disebut sebuah tabel konten eksternal.

enter image description here

Buat Tabel

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

Perhatikan bahwa kita harus menggunakan FTS4 untuk melakukan ini daripada FTS3. FTS4 tidak didukung di Android sebelum API versi 11. Anda bisa (1) hanya menyediakan fungsionalitas pencarian untuk API> = 11, atau (2) menggunakan tabel FTS3 (tetapi ini berarti database akan lebih besar karena kolom teks lengkap ada di kedua database).

Isi Tabel

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

(Sekali lagi, ada cara yang lebih baik dalam melakukan sisipan dibandingkan dengan execSQL. Saya hanya menggunakannya untuk keterbacaannya.)

Jika Anda mencoba melakukan kueri FTS sekarang fts_example_table Anda tidak akan mendapatkan hasil. Alasannya adalah bahwa mengubah satu tabel tidak secara otomatis mengubah tabel lainnya. Anda harus memperbarui tabel FTS secara manual:

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

(Itu docid seperti halnya rowid untuk tabel biasa.) Anda harus memastikan untuk memperbarui tabel FTS (sehingga dapat memperbarui indeks) setiap kali Anda membuat perubahan (INSERT, DELETE, UPDATE) ke tabel konten eksternal. Ini bisa jadi rumit. Jika Anda hanya membuat database yang terpopulasi, Anda dapat melakukannya

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

yang akan membangun kembali seluruh meja. Ini bisa lambat, jadi bukan sesuatu yang ingin Anda lakukan setelah setiap perubahan kecil. Anda akan melakukannya setelah menyelesaikan semua sisipan pada tabel konten eksternal. Jika Anda memang perlu menjaga agar databas sinkron secara otomatis, Anda dapat menggunakannya pemicu. Kesini dan gulir ke bawah sedikit untuk menemukan arah.

Permintaan Databases

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

Ini sama seperti sebelumnya, kecuali kali ini Anda hanya memiliki akses ke text_column (dan docid). Bagaimana jika Anda perlu mendapatkan data dari kolom lain di tabel konten eksternal? Sejak itu docid dari tabel FTS sesuai dengan rowid (dan dalam hal ini _id) dari tabel konten eksternal, Anda dapat menggunakan gabung. (Terimakasih untuk jawaban ini untuk membantu dengan itu.)

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);

Bacaan lebih lanjut

Pergi melalui dokumen-dokumen ini dengan hati-hati untuk melihat cara lain menggunakan tabel virtual FTS:

catatan tambahan


98
2018-04-28 17:46



Jangan lupa ketika menggunakan konten dari untuk membangun kembali meja fts.

Saya melakukan ini dengan pemicu saat memperbarui, menyisipkan, menghapus


1
2017-08-31 08:54