我很难理解如何在Android上使用全文搜索(FTS)。我已经读过SQLite documentation on the FTS3 and FTS4 extensions。而且我知道it's possible to do on Android。但是,我很难找到我能理解的任何例子。
基本数据库模型
SQLite数据库表(名为example_table
)具有4列。但是,对于全文搜索,仅需要索引一列(名为text_column
)。 text_column
的每一行都包含长度在0到1000个单词之间的文本。行的总数大于10,000。
text_column
执行FTS查询? 附加说明:
example_table
)将是inefficient for non-FTS queries。 text_column
的重复条目将是不可取的。 This post建议使用external content table。 最佳答案
最基本的答案
我在下面使用普通的sql,以便所有内容都尽可能清晰易读。在您的项目中,您可以使用Android便捷方法。下面使用的db
对象是SQLiteDatabase的实例。
Create FTS Table
db.execSQL("CREATE VIRTUAL TABLE fts_table USING fts3 ( col_1, col_2, text_column )");
这可以在扩展的
onCreate()
类的SQLiteOpenHelper
方法中进行。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来执行此操作。 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_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)时,必须确保更新FTS表(以便它可以更新索引)。 。这可能会很麻烦。如果您只创建一个预先填充的数据库,则可以执行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虚拟表的其他方式:
附加条款
UNION
或检查 PRAGMA compile_options
似乎很困难)。非常不幸。如果此区域有更新,请添加评论。 关于android - Android中的全文本搜索示例,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/29815248/