android SQLite:大表中的高效子串搜索

ndasle7k  于 2023-05-21  发布在  Android
关注(0)|答案(5)|浏览(201)

我正在开发一个Android应用程序,它必须在一个大表中执行子字符串搜索(大约有500'000个街道和位置名称的条目,所以每个条目只有几个字)。

CREATE TABLE Elements (elementID INTEGER, type INTEGER, name TEXT, data BLOB)

请注意,所有条目中只有20%在“name”列中包含字符串。
执行以下查询几乎需要2分钟:

SELECT elementID, name FROM Elements WHERE name LIKE %foo%

我现在尝试使用FTS 3来加快查询速度。这是相当成功的,查询时间减少到1分钟(令人惊讶的是,数据库文件大小只增加了5%,这对我的目的也很好)。
问题是,FTS 3似乎不支持子串搜索,即。如果我想在“foobar”和“foobar”中找到“bar”,我只得到“foobar”,尽管我需要这两个结果。
其实我有两个问题:
1.是否有可能进一步加快查询速度?我的目标是30秒的查询,但我不知道这是否现实...
1.如何使用FTS 3进行真实的子串搜索?

wpx232ag

wpx232ag1#

**解决方案1:**如果您可以将数据库中的每个字符作为一个单独的单词,则可以使用短语查询来搜索子字符串。

例如,假设“my_table”包含单个列“person”:

person
------
John Doe
Jane Doe

你可以把它改成

person
------
J o h n D o e
J a n e D o e

要搜索子字符串“ohn”,请使用短语查询:

SELECT * FROM my_table WHERE person MATCH '"o h n"'

注意“JohnD”将匹配“John Doe”,这可能不是所希望的。要修复它,请将原始字符串中的空格字符更改为其他字符。
例如,您可以将空格字符替换为“$”:

person
------
J o h n $ D o e
J a n e $ D o e

**方案二:**按照方案一的思路,您可以使用自定义分词器将每个字符作为一个单词,并使用短语查询来查询子字符串。

与解决方案1相比,它的优点是您不必在数据中添加空格,这可能会不必要地增加数据库的大小。
缺点是您必须实现自定义标记器。幸运的是,我有one ready for you。代码是用C编写的,所以你必须弄清楚如何将它与Java代码集成。

anauzrmj

anauzrmj2#

您应该为数据库上的name列添加一个索引,这应该会大大加快查询速度。
我相信SQLite3支持子字符串匹配如下:

SELECT * FROM Elements WHERE name MATCH '*foo*';

http://www.sqlite.org/fts3.html#section_3

xmakbtuz

xmakbtuz3#

我正面临着一些类似于你的问题。这里是我的建议,尝试创建一个翻译表,将所有的单词翻译成数字。然后搜索数字而不是单词。
请让我知道这是否有帮助。

lfapxunr

lfapxunr4#

SQLITE现在支持三元组索引(从v3.34.0开始),这应该有助于加快子字符串查询:
与全文查询一起使用时,包含少于3个unicode字符的子字符串不匹配任何行。如果LIKE或GLOB模式不包含至少一个非通配符unicode字符序列,FTS5福尔斯退到整个表的线性扫描。

CREATE VIRTUAL TABLE tri USING fts5(a, tokenize="trigram");

https://www.sqlite.org/fts5.html#trigramidx

u1ehiz5o

u1ehiz5o5#

我不确定是否能加快速度,因为您使用的是sqllite,但是对于子字符串搜索,我做了如下操作

SET @foo_bar = 'foo bar'
SELECT * FROM table WHERE name LIKE '%' + REPLACE(@foo_bar, ' ', '%') + '%'

当然,这仅返回在单词“bar”之前具有单词“foo”的记录。

相关问题