Android中的全文搜索示例

Sur*_*gch 85 sqlite android full-text-search

我很难理解如何在Android上使用全文搜索(FTS).我已经阅读了关于FTS3和FTS4扩展SQLite文档.而且我知道可以在Android上进行.但是,我很难找到任何我能理解的例子.

基本数据库模型

SQLite数据库表(已命名example_table)有4列.但是,只有一列(已命名text_column)需要为全文搜索编制索引.每行text_column包含长度从0到1000字不等的文本.总行数大于10,000.

  • 您将如何设置表和/或FTS虚拟表?
  • 你将如何执行FTS查询text_column

补充说明:

  • 因为只需要索引一列,所以仅使用FTS表(和删除example_table)对于非FTS查询来说效率低下.
  • 对于这样大的表,存储text_columnFTS表中的重复条目是不合需要的.这篇文章建议使用外部内容表.
  • 外部内容表使用FTS4,但在Android API 11之前不支持 FTS4 .答案可以假设API> = 11,但是评论支持较低版本的选项会很有帮助.
  • 更改原始表中的数据不会自动更新FTS表(反之亦然).在这个基本示例中,不需要在答案中包含触发器,但仍然会有所帮助.

Sur*_*gch 112

最基本的答案

我正在使用下面的简单sql,以便尽可能清晰可读.在您的项目中,您可以使用Android便捷方法.下面db使用的对象是SQLiteDatabase的一个实例.

创建FTS表

db.execSQL("CREATE VIRTUAL TABLE fts_table USING fts3 ( col_1, col_2, text_column )");
Run Code Online (Sandbox Code Playgroud)

这可以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.')");
Run Code Online (Sandbox Code Playgroud)

这将是更好地使用SQLiteDatabase#插入准备语句execSQL.

查询FTS表

String[] selectionArgs = { searchString };
Cursor cursor = db.rawQuery("SELECT * FROM fts_table WHERE fts_table MATCH ?", selectionArgs);
Run Code Online (Sandbox Code Playgroud)

您还可以使用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)");
Run Code Online (Sandbox Code Playgroud)

请注意,我们必须使用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.')");
Run Code Online (Sandbox Code Playgroud)

(同样,插入比插入更好的方法execSQL.我只是因为它的可读性而使用它.)

如果您现在尝试进行FTS查询,则fts_example_table无法获得任何结果.原因是更改一个表不会自动更改另一个表.您必须手动更新FTS表:

db.execSQL("INSERT INTO fts_example_table (docid, text_column) SELECT _id, text_column FROM example_table");
Run Code Online (Sandbox Code Playgroud)

(docid就像rowid常规表一样.)每次对外部内容表进行更改(INSERT,DELETE,UPDATE)时,都必须确保更新FTS表(以便它可以更新索引).这可能会很麻烦.如果您只是制作预填充数据库,则可以这样做

db.execSQL("INSERT INTO fts_example_table(fts_example_table) VALUES('rebuild')");
Run Code Online (Sandbox Code Playgroud)

这将重建整个表.但这可能很慢,因此在每次微小的改变之后,这都不是你想做的事情.完成外部内容表上的所有插入后,您将执行此操作.如果确实需要自动保持数据库同步,则可以使用触发器.到这里向下滚动一点以找到方向.

查询数据库

String[] selectionArgs = { searchString };
Cursor cursor = db.rawQuery("SELECT * FROM fts_example_table WHERE fts_example_table MATCH ?", selectionArgs);
Run Code Online (Sandbox Code Playgroud)

这和以前一样,除了这次你只能访问text_column(和docid).如果您需要从外部内容表中的其他列获取数据,该怎么办?由于docidFTS表与外部内容表的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);
Run Code Online (Sandbox Code Playgroud)

进一步阅读

仔细阅读这些文档,了解使用FTS虚拟表的其他方法:

补充说明


归档时间:

查看次数:

27221 次

最近记录:

8 年,11 月 前