最基本的答案
我用下面让一切都清晰可读尽可能普通的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方法。请注意0关键字。
Fuller答案
上面的虚拟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.')");
(同样,也有更好的方式执行插入比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')");
这将重建整个表。但是,这可能会很慢,所以在每次小改动之后,这都不是你想要做的。在完成外部内容表中的所有插入之后,您可以执行此操作。如果您确实需要自动同步数据库,则可以使用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虚拟表的其他方式:
附加说明
证据充分的问题,我对付你来到这里任意downvote。 – Mekap