Мне сложно понять, как использовать полнотекстовый поиск (FTS) с Android. Я прочитал документацию SQLite о расширениях FTS3 и FTS4 . И я знаю, что это возможно на Android . Однако мне трудно найти какие-либо примеры, которые я могу понять.
Базовая модель базы данных
Таблица базы данных SQLite (названная example_table
) имеет 4 столбца. Однако есть только один столбец (названный text_column
), который нужно проиндексировать для полнотекстового поиска. Каждая строка text_column
содержит текст длиной от 0 до 1000 слов. Общее количество строк больше 10 000.
- Как бы вы настроили стол и / или виртуальный стол FTS?
- Как бы вы выполнили запрос FTS
text_column
?
Дополнительные примечания:
- Поскольку необходимо проиндексировать только один столбец, использование только таблицы FTS (и ее удаление
example_table
) будет неэффективным для запросов, отличных от FTS . - Для такой большой таблицы
text_column
нежелательно хранить повторяющиеся записи в таблице FTS. В этом сообщении предлагается использовать внешнюю таблицу содержимого . - Таблицы внешнего содержимого используют FTS4, но FTS4 не поддерживается до Android API 11 . Ответ может предполагать, что API> = 11, но было бы полезно прокомментировать варианты поддержки более низких версий.
- Изменение данных в исходной таблице не приводит к автоматическому обновлению таблицы FTS (и наоборот). Включать триггеры в ваш ответ не обязательно для этого базового примера, но тем не менее было бы полезно.
android
sqlite
full-text-search
Suragch
источник
источник
Ответы:
Самый простой ответ
Я использую простой 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 # . Обратите внимание на
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)");
Обратите внимание, что для этого мы должны использовать FTS4, а не FTS3. FTS4 не поддерживается в Android до версии 11 API. Вы можете либо (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.')");
(Опять же, есть лучшие способы вставки do, чем с
execSQL
. Я использую его просто для удобства чтения.)Если вы попытаетесь выполнить запрос FTS сейчас,
fts_example_table
вы не получите результатов. Причина в том, что изменение одной таблицы не приводит к автоматическому изменению другой таблицы. Вам необходимо вручную обновить таблицу FTS:db.execSQL("INSERT INTO fts_example_table (docid, text_column) SELECT _id, text_column FROM example_table");
(Это
docid
похоже наrowid
обычную таблицу.) Вы должны обязательно обновлять таблицу FTS (чтобы она могла обновлять индекс) каждый раз, когда вы вносите изменения (INSERT, DELETE, UPDATE) во внешнюю таблицу содержимого. Это может стать громоздким. Если вы создаете только предварительно заполненную базу данных, вы можете сделать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:
Дополнительные примечания
UNION
или проверкаPRAGMA compile_options
). Очень жаль. Пожалуйста, добавьте комментарий, если в этой области есть обновления.источник
Не забывайте при использовании содержимого from для перестройки таблицы fts.
Я делаю это с триггером на обновление, вставку, удаление
источник
INSERT INTO foo_fts VALUES("rebuild")