最基本的答案
我使用下面的普通 sql,以便一切都尽可能清晰易读。在您的项目中,您可以使用 Android 便捷方法。下面使用的db 对象是SQLiteDatabase 的一个实例。
Create FTS Table
db.execSQL("CREATE VIRTUAL TABLE fts_table USING fts3 ( col_1, col_2, text_column )");
这可以放在扩展 SQLiteOpenHelper 类的 onCreate() 方法中。
Populate FTS Table
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 或prepared statements 比使用execSQL 更好。
Query FTS Table
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 表将包含索引,但不包含常规表中的实际数据。相反,它将有一个指向常规表内容的链接。这称为external content table。
创建表格
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 来执行此操作。 API 版本 11 之前的 Android 不支持 FTS4。您可以 (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_example_table 上进行 FTS 查询,您将得不到任何结果。原因是更改一张表不会自动更改另一张表。您必须手动更新 FTS 表:
db.execSQL("INSERT INTO fts_example_table (docid, text_column) SELECT _id, text_column FROM example_table");
(docid 类似于常规表的rowid。)每次进行更改(INSERT、DELETE、 UPDATE)到外部内容表。这会变得很麻烦。如果你只是制作一个预填充的数据库,你可以这样做
db.execSQL("INSERT INTO fts_example_table(fts_example_table) VALUES('rebuild')");
这将重建整个表。不过,这可能会很慢,所以这不是您在每次小改动后都想做的事情。您将在完成外部内容表上的所有插入后执行此操作。如果确实需要自动保持数据库同步,可以使用triggers。 Go here 并向下滚动一点以查找路线。
查询数据库
String[] selectionArgs = { searchString };
Cursor cursor = db.rawQuery("SELECT * FROM fts_example_table WHERE fts_example_table MATCH ?", selectionArgs);
这和以前一样,只是这次你只能访问text_column(和docid)。如果您需要从外部内容表中的其他列获取数据怎么办?由于 FTS 表的 docid 与外部内容表的 rowid(在本例中为 _id)匹配,因此您可以使用连接。 (感谢this answer 的帮助。)
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 虚拟表的其他方法:
附加说明