[英]Full text search example in Android
我很难理解如何在Android上使用全文搜索(FTS)。 我已经阅读了关于FTS3和FTS4扩展的SQLite文档 。 而且我知道可以在Android上进行 。 但是,我很难找到任何我能理解的例子。
SQLite数据库表(名为example_table
)有4列。 但是,只有一列(名为text_column
)需要为全文搜索编制索引。 text_column
每一行都包含长度从0到1000字不等的文本。 总行数大于10,000。
text_column
上执行FTS查询? 补充说明:
example_table
) 对于非FTS查询来说效率低下 。 text_column
重复条目是不合需要的。 这篇文章建议使用外部内容表 。 我正在使用下面的简单sql,以便尽可能清晰可读。 在您的项目中,您可以使用Android便捷方法。 下面使用的db
对象是SQLiteDatabase的一个实例。
db.execSQL("CREATE VIRTUAL TABLE fts_table USING fts3 ( col_1, col_2, text_column )");
这可以放在扩展的SQLiteOpenHelper
类的onCreate()
方法中。
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
语句比execSQL
。
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。 在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_example_table
上执行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
)。 如果您需要从外部内容表中的其他列获取数据,该怎么办? 由于FTS表的docid
与外部内容表的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表时不要忘记。
我通过更新,插入,删除触发器执行此操作
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.