Пример полнотекстового поиска в Android

мне трудно понять, как использовать полнотекстовый поиск (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 (и наоборот). В том числе триггеры в вашем ответе нет необходимости для этого основного примера, но тем не менее было бы полезно.

2 ответов


Самый Простой Ответ

я использую простой sql ниже, чтобы все было максимально понятным и читаемым. В вашем проекте вы можете использовать удобные методы Android. The 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#query метод. Примечание MATCH ключевое слово.

Более Полный Ответ

виртуальная таблица FTS выше имеет проблему с ней. Каждая колонка индексируется, но это пустая трата пространства и ресурсов, если некоторые столбцы не нужно индексировать. Единственный столбец, который нуждается в индексе FTS, вероятно, является text_column.

для решения этой проблемы мы будем использовать комбинацию обычной таблицы и виртуальной таблицы FTS. Таблица FTS будет содержать индекс, но не фактические данные из обычной таблицы. Вместо этого он будет иметь ссылку на содержимое обычной таблицы. Это называется внешний контент таблица.

enter image description here

создать таблицы

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 до версии API 11. Вы можете либо (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:

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

(The docid как rowid для обычной таблице.) Вы должны обязательно обновить Таблица 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_columndocid). Что делать, если вам нужно получить данные из других столбцов во внешней таблице содержимого? С 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:

дополнительные Примечания


Не забывайте при использовании содержимого из перестроить таблицу fts.

Я делаю это с триггером на update, insert, delete