Trudno mi zrozumieć, jak korzystać z wyszukiwania pełnotekstowego (FTS) w systemie Android. Przeczytałem dokumentację SQLite dotyczącą rozszerzeń FTS3 i FTS4 . Wiem, że można to zrobić na Androidzie . Trudno mi jednak znaleźć jakiekolwiek przykłady, które mogę zrozumieć.
Podstawowy model bazy danych
Tabela bazy danych SQLite (nazwana example_table
) ma 4 kolumny. Jednak istnieje tylko jedna kolumna (nazwana text_column
), która musi zostać zindeksowana w celu wyszukiwania pełnotekstowego. Każdy wiersz text_column
zawiera tekst o długości od 0 do 1000 słów. Całkowita liczba wierszy jest większa niż 10 000.
- Jak skonfigurowałbyś stół i / lub wirtualny stół FTS?
- Jak wykonałbyś zapytanie FTS na
text_column
?
Dodatkowe uwagi:
- Ponieważ tylko jedna kolumna musi być indeksowana, użycie tylko tabeli FTS (i usuwanie
example_table
) byłoby nieefektywne w przypadku zapytań innych niż FTS . - W przypadku tak dużej tabeli przechowywanie zduplikowanych wpisów
text_column
w tabeli FTS byłoby niepożądane. Ten post sugeruje użycie zewnętrznej tabeli zawartości . - Tabele zawartości zewnętrznej używają FTS4, ale FTS4 nie jest obsługiwany przed Android API 11 . Odpowiedź może zakładać, że API> = 11, ale skomentowanie opcji obsługi niższych wersji byłoby pomocne.
- Zmiana danych w oryginalnej tabeli nie powoduje automatycznej aktualizacji tabeli FTS (i odwrotnie). Uwzględnianie wyzwalaczy w odpowiedzi nie jest konieczne w tym podstawowym przykładzie, ale mimo wszystko byłoby pomocne.
android
sqlite
full-text-search
Suragch
źródło
źródło
Odpowiedzi:
Najbardziej podstawowa odpowiedź
Używam zwykłego sql poniżej, aby wszystko było tak jasne i czytelne, jak to tylko możliwe. W swoim projekcie możesz skorzystać z wygodnych metod Androida.
db
Przedmiot używany poniżej jest przykładem SQLiteDatabase .Utwórz tabelę FTS
db.execSQL("CREATE VIRTUAL TABLE fts_table USING fts3 ( col_1, col_2, text_column )");
Może to dotyczyć
onCreate()
metody rozszerzonejSQLiteOpenHelper
klasy.Wypełnij 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.')");
Byłoby lepiej użyć SQLiteDatabase # insert lub przygotowanych instrukcji niż
execSQL
.Zapytanie o tabelę FTS
String[] selectionArgs = { searchString }; Cursor cursor = db.rawQuery("SELECT * FROM fts_table WHERE fts_table MATCH ?", selectionArgs);
Możesz również użyć metody zapytania SQLiteDatabase # . Zanotuj
MATCH
słowo kluczowe.Pełniejsza odpowiedź
Powyższa wirtualna tabela FTS ma z tym problem. Każda kolumna jest indeksowana, ale jest to strata miejsca i zasobów, jeśli niektóre kolumny nie muszą być indeksowane. Jedyną kolumną, która wymaga indeksu FTS, jest prawdopodobnie
text_column
.Aby rozwiązać ten problem, użyjemy kombinacji zwykłej tabeli i wirtualnej tabeli FTS. Tabela FTS będzie zawierać indeks, ale żadnych rzeczywistych danych ze zwykłej tabeli. Zamiast tego będzie zawierał link do zawartości zwykłej tabeli. Nazywa się to tabelą zawartości zewnętrznej .
Utwórz tabele
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)");
Zauważ, że musimy do tego użyć FTS4 zamiast FTS3. FTS4 nie jest obsługiwany w Androidzie przed wersją API 11. Możesz albo (1) zapewnić funkcjonalność wyszukiwania tylko dla API> = 11, albo (2) użyć tabeli FTS3 (ale to oznacza, że baza danych będzie większa ponieważ istnieje kolumna pełnego tekstu w obu bazach danych).
Wypełnij tabele
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.')");
(Ponownie, są lepsze sposoby na wstawianie niż z
execSQL
. Używam go tylko ze względu na jego czytelność).Jeśli spróbujesz teraz wykonać zapytanie FTS
fts_example_table
, nie uzyskasz żadnych wyników. Powodem jest to, że zmiana jednej tabeli nie zmienia automatycznie drugiej tabeli. Musisz ręcznie zaktualizować tabelę FTS:db.execSQL("INSERT INTO fts_example_table (docid, text_column) SELECT _id, text_column FROM example_table");
(To
docid
jest jakrowid
dla zwykłej tabeli.) Musisz upewnić się, że zaktualizujesz tabelę FTS (tak, aby mogła aktualizować indeks) za każdym razem, gdy dokonujesz zmiany (INSERT, DELETE, UPDATE) w zewnętrznej tabeli zawartości. Może to być kłopotliwe. Jeśli tworzysz tylko wstępnie wypełnioną bazę danych, możesz to zrobićdb.execSQL("INSERT INTO fts_example_table(fts_example_table) VALUES('rebuild')");
który odbuduje cały stół. Może to jednak być powolne, więc nie jest to coś, co chcesz robić po każdej drobnej zmianie. Zrobiłbyś to po zakończeniu wszystkich wstawień w zewnętrznej tabeli zawartości. Jeśli musisz automatycznie synchronizować bazy danych, możesz użyć wyzwalaczy . Przejdź tutaj i przewiń trochę w dół, aby znaleźć wskazówki.
Przeszukuj bazy danych
String[] selectionArgs = { searchString }; Cursor cursor = db.rawQuery("SELECT * FROM fts_example_table WHERE fts_example_table MATCH ?", selectionArgs);
To jest to samo co poprzednio, z tym że tym razem masz dostęp tylko do
text_column
(idocid
). Co się stanie, jeśli chcesz pobrać dane z innych kolumn w tabeli zawartości zewnętrznej? Ponieważdocid
tabela FTS pasuje dorowid
(iw tym przypadku_id
) tabeli zawartości zewnętrznej, możesz użyć sprzężenia. (Dzięki tej odpowiedzi za pomoc.)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);
Dalsze czytanie
Przejrzyj dokładnie te dokumenty, aby zobaczyć inne sposoby korzystania z wirtualnych tabel FTS:
Dodatkowe uwagi
UNION
lub sprawdzenia,PRAGMA compile_options
jak się wydaje). Bardzo niefortunne. Proszę dodać komentarz, jeśli jest aktualizacja w tym obszarze.źródło
Nie zapomnij o używaniu zawartości z do odbudowania tabeli fts.
Robię to z wyzwalaczem podczas aktualizacji, wstawiania, usuwania
źródło
INSERT INTO foo_fts VALUES("rebuild")