最基本的答案
我在下面使用普通的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#插入或准备语句比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表将包含索引,但不包含常规表中的任何实际数据。相反,它将具有到常规表内容的链接。这称为外部内容表。
创建表
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。Android之前的API版本11不支持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.')");
(同样,做插入比有更好的方法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
常规表。)每次对外部内容表进行更改(INSERT,DELETE,UPDATE)时,必须确保更新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_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虚拟表的其他方式:
补充说明