Grundlegendste Antwort
Ich benutze das einfache SQL unten, damit alles so klar und lesbar wie möglich ist. In Ihrem Projekt können Sie die Android-Convenience-Methoden verwenden. Das db
unten verwendete Objekt ist eine Instanz von SQLiteDatabase .
FTS-Tabelle erstellen
db.execSQL("CREATE VIRTUAL TABLE fts_table USING fts3 ( col_1, col_2, text_column )");
Dies könnte in die onCreate()
Methode Ihrer erweiterten SQLiteOpenHelper
Klasse gehen.
Füllen Sie die FTS-Tabelle aus
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.')");
Es wäre besser, SQLiteDatabase # insert oder vorbereitete Anweisungen zu verwenden als execSQL
.
FTS-Tabelle abfragen
String[] selectionArgs = { searchString };
Cursor cursor = db.rawQuery("SELECT * FROM fts_table WHERE fts_table MATCH ?", selectionArgs);
Sie können auch die SQLiteDatabase # -Abfragemethode verwenden. Beachten Sie das MATCH
Schlüsselwort.
Vollständigere Antwort
Die obige virtuelle FTS-Tabelle weist ein Problem auf. Jede Spalte ist indiziert, dies ist jedoch eine Verschwendung von Speicherplatz und Ressourcen, wenn einige Spalten nicht indiziert werden müssen. Die einzige Spalte, die einen FTS-Index benötigt, ist wahrscheinlich die text_column
.
Um dieses Problem zu lösen, verwenden wir eine Kombination aus einer regulären Tabelle und einer virtuellen FTS-Tabelle. Die FTS-Tabelle enthält den Index, jedoch keine der tatsächlichen Daten aus der regulären Tabelle. Stattdessen wird ein Link zum Inhalt der regulären Tabelle angezeigt. Dies wird als externe Inhaltstabelle bezeichnet .
Erstellen Sie die Tabellen
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)");
Beachten Sie, dass wir dafür FTS4 verwenden müssen, anstatt FTS3. FTS4 wird in Android vor API-Version 11 nicht unterstützt. Sie können entweder (1) nur Suchfunktionen für API> = 11 bereitstellen oder (2) eine FTS3-Tabelle verwenden (dies bedeutet jedoch, dass die Datenbank größer ist, da die Volltextspalte vorhanden ist in beiden Datenbanken).
Füllen Sie die Tabellen
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.')");
(Auch hier gibt es bessere Möglichkeiten zum Einfügen von Beilagen als mit execSQL
. Ich verwende es nur wegen seiner Lesbarkeit.)
Wenn Sie jetzt versuchen würden, eine FTS-Abfrage durchzuführen fts_example_table
, würden Sie keine Ergebnisse erhalten. Der Grund ist, dass das Ändern einer Tabelle die andere Tabelle nicht automatisch ändert. Sie müssen die FTS-Tabelle manuell aktualisieren:
db.execSQL("INSERT INTO fts_example_table (docid, text_column) SELECT _id, text_column FROM example_table");
(Dies docid
ist wie rowid
bei einer regulären Tabelle.) Sie müssen sicherstellen, dass die FTS-Tabelle bei jeder Änderung (INSERT, DELETE, UPDATE) an der externen Inhaltstabelle aktualisiert wird (damit der Index aktualisiert werden kann). Dies kann umständlich werden. Wenn Sie nur eine vorab ausgefüllte Datenbank erstellen, können Sie dies tun
db.execSQL("INSERT INTO fts_example_table(fts_example_table) VALUES('rebuild')");
Dadurch wird die gesamte Tabelle neu erstellt. Dies kann jedoch langsam sein, sodass Sie es nicht nach jeder kleinen Änderung tun möchten. Sie würden dies tun, nachdem Sie alle Einfügungen in der externen Inhaltstabelle abgeschlossen haben. Wenn Sie die Datenbanken automatisch synchronisieren müssen, können Sie Trigger verwenden . Gehen Sie hierher und scrollen Sie ein wenig nach unten, um eine Wegbeschreibung zu finden.
Fragen Sie die Datenbanken ab
String[] selectionArgs = { searchString };
Cursor cursor = db.rawQuery("SELECT * FROM fts_example_table WHERE fts_example_table MATCH ?", selectionArgs);
Dies ist das gleiche wie zuvor, außer dass Sie diesmal nur Zugriff auf text_column
(und docid
) haben. Was ist, wenn Sie Daten aus anderen Spalten in der externen Inhaltstabelle abrufen müssen? Da die docid
der FTS-Tabelle mit der rowid
(und in diesem Fall _id
) der externen Inhaltstabelle übereinstimmt , können Sie einen Join verwenden. (Dank dieser Antwort für die Hilfe dabei.)
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);
Weiterführende Literatur
Sehen Sie sich diese Dokumente sorgfältig an, um weitere Möglichkeiten zur Verwendung virtueller FTS-Tabellen zu finden:
Zusätzliche Bemerkungen
- Set-Operatoren (AND, OR, NOT) in SQLite FTS-Abfragen verfügen über die Standardabfragesyntax und die erweiterte Abfragesyntax . Leider unterstützt Android die Enhanced Query Syntax anscheinend nicht (siehe hier , hier , hier und hier ). Das bedeutet, dass das Mischen von AND und OR schwierig wird (was die Verwendung
UNION
oder Überprüfung erfordert PRAGMA compile_options
). Äußerst unglücklich. Bitte fügen Sie einen Kommentar hinzu, wenn es in diesem Bereich ein Update gibt.