Android 中的 Sqlite 全文搜索对非英语字符的 Unicode 支持
Unicode support for non-English characters with Sqlite Full Text Search in Android
滚动到末尾以跳过说明。
背景
在我的 Android 应用程序中,我想使用非英语 Unicode 文本字符串来搜索存储在 SQLite 数据库中的文本 documents/fields 中的匹配项。我了解到(所以我认为)我需要做的是实施 Full Text Search with fts3/fts4, so that is what I have been working on learning for the past couple days. FTS is supported by Android, as is shown in the documentation Storing and Searching for Data and in the blog post Android Quick Tip: Using SQLite FTS Tables.
问题
一切看起来都不错,但后来我阅读了 2012 年 3 月的博客 post The sorry state of SQLite full text search on Android,其中说
The first step when building a full text search index is to break down
the textual content into words, aka tokens. Those tokens are then
entered into a special index which lets SQLite perform very fast
searches based on a token (or a set of tokens).
SQLite has two built-in tokenizers, and they both only consider tokens
consisting of US ASCII characters. All other, non-US ASCII characters
are considered whitespace.
在那之后我还发现 this Whosebug answer by @CL.(根据标签和声誉,他似乎是 SQLite 专家)回答了有关匹配具有不同变音符号的越南字母的问题:
You must create the FTS table with a tokenizer that can handle Unicode
characters, i.e., ICU or UNICODE61.
Please note that these tokenizers might not be available on all
Android versions, and that the Android API does not expose any
functions for adding user-defined tokenizers.
This 2011 SO answer 似乎证实 Android 不支持两个基本 simple
和 porter
之外的分词器。
现在是2015年了,这个情况有更新吗?我需要为所有使用我的应用程序的人提供全文搜索支持,而不仅仅是使用新手机的人(即使最新的 Android 版本现在支持它)。
可能的部分解决方案?
我很难相信 FTS 根本不能与 Unicode 一起工作。 simple
分词器的 documentation 表示
A term is a contiguous sequence of eligible characters, where eligible
characters are all alphanumeric characters and all characters with
Unicode codepoint values greater than or equal to 128. All other
characters are discarded when splitting a document into terms. Their
only contribution is to separate adjacent terms. (emphasis added)
这让我希望 Android 仍然可以支持一些基本的 Unicode 功能,即使不支持大写和变音符号(以及具有不同 Unicode 代码点的各种其他等效字母形式)。
我的主要问题
如果我只使用由空格分隔的文字 Unicode 字符串标记,我可以在 Android 中将 SQLite FTS 与非英语 Unicode 文本(代码点 > 128)一起使用吗? (也就是说,我正在搜索文本中出现的确切字符串。)
更新
- unicode61 tokenizer is available in SQLite version 3.7.13. This tokenizer supports "full unicode case folding" and "recognizes unicode space and punctuation characters." Android Lollipop (API 20+) uses SQLite 3.8。
Unicode 字符的处理方式与 'normal' 字母相同,因此您可以在 FTS 数据和搜索词中使用它们。 (前缀搜索也应该有效。)
问题是 Unicode 字符未 规范化 ,即 所有 字符都被视为字母(即使它们实际上是标点符号(―†),或其他非字母字符 (☺♫)),upper/lowercase 未合并,变音符号未删除。
如果您想正确处理这些情况,则必须在将文档插入数据库之前以及在使用搜索词之前手动执行这些规范化。
补充回答
我最终按照@CL 的建议进行了操作,并成功地实现了使用 Unicode 的全文搜索。这些是我遵循的基本步骤:
- 将不属于单词的所有 Unicode 字符 (>= 128) 替换为 space 字符。
- (可选)用更通用的字符替换特定字符。例如,
ē
、è
和 é
都可以替换为 e
(如果需要这种通用搜索)。这不是必需的,但如果你不这样做,那么搜索 é
将只会 return 带有 é
的文档,而搜索 e
只会 [=45] =] 带有 e
的文档(而不是 é
)。
- 使用在步骤 1 和 2 中创建的修改后的文本填充虚拟 FTS table。
- 使用未修改的文本填充您的正常 table。当然,架构和文档数量必须与您创建 FTS 时相同 table。
- Link 虚拟 FTS table 与您的普通文本 table/column 使用外部内容 table 这样您就不会存储修改后文本的副本,仅从该文本创建的文档 ID。
请阅读 以获取有关如何创建 FTS table 和 link 正常 table 的说明。这花了很长时间才弄清楚,但最终即使对大量文档也能进行非常快速的全文搜索。
如果您需要更多详细信息,请在下面发表评论。
滚动到末尾以跳过说明。
背景
在我的 Android 应用程序中,我想使用非英语 Unicode 文本字符串来搜索存储在 SQLite 数据库中的文本 documents/fields 中的匹配项。我了解到(所以我认为)我需要做的是实施 Full Text Search with fts3/fts4, so that is what I have been working on learning for the past couple days. FTS is supported by Android, as is shown in the documentation Storing and Searching for Data and in the blog post Android Quick Tip: Using SQLite FTS Tables.
问题
一切看起来都不错,但后来我阅读了 2012 年 3 月的博客 post The sorry state of SQLite full text search on Android,其中说
The first step when building a full text search index is to break down the textual content into words, aka tokens. Those tokens are then entered into a special index which lets SQLite perform very fast searches based on a token (or a set of tokens).
SQLite has two built-in tokenizers, and they both only consider tokens consisting of US ASCII characters. All other, non-US ASCII characters are considered whitespace.
在那之后我还发现 this Whosebug answer by @CL.(根据标签和声誉,他似乎是 SQLite 专家)回答了有关匹配具有不同变音符号的越南字母的问题:
You must create the FTS table with a tokenizer that can handle Unicode characters, i.e., ICU or UNICODE61.
Please note that these tokenizers might not be available on all Android versions, and that the Android API does not expose any functions for adding user-defined tokenizers.
This 2011 SO answer 似乎证实 Android 不支持两个基本 simple
和 porter
之外的分词器。
现在是2015年了,这个情况有更新吗?我需要为所有使用我的应用程序的人提供全文搜索支持,而不仅仅是使用新手机的人(即使最新的 Android 版本现在支持它)。
可能的部分解决方案?
我很难相信 FTS 根本不能与 Unicode 一起工作。 simple
分词器的 documentation 表示
A term is a contiguous sequence of eligible characters, where eligible characters are all alphanumeric characters and all characters with Unicode codepoint values greater than or equal to 128. All other characters are discarded when splitting a document into terms. Their only contribution is to separate adjacent terms. (emphasis added)
这让我希望 Android 仍然可以支持一些基本的 Unicode 功能,即使不支持大写和变音符号(以及具有不同 Unicode 代码点的各种其他等效字母形式)。
我的主要问题
如果我只使用由空格分隔的文字 Unicode 字符串标记,我可以在 Android 中将 SQLite FTS 与非英语 Unicode 文本(代码点 > 128)一起使用吗? (也就是说,我正在搜索文本中出现的确切字符串。)
更新
- unicode61 tokenizer is available in SQLite version 3.7.13. This tokenizer supports "full unicode case folding" and "recognizes unicode space and punctuation characters." Android Lollipop (API 20+) uses SQLite 3.8。
Unicode 字符的处理方式与 'normal' 字母相同,因此您可以在 FTS 数据和搜索词中使用它们。 (前缀搜索也应该有效。)
问题是 Unicode 字符未 规范化 ,即 所有 字符都被视为字母(即使它们实际上是标点符号(―†),或其他非字母字符 (☺♫)),upper/lowercase 未合并,变音符号未删除。
如果您想正确处理这些情况,则必须在将文档插入数据库之前以及在使用搜索词之前手动执行这些规范化。
补充回答
我最终按照@CL 的建议进行了操作,并成功地实现了使用 Unicode 的全文搜索。这些是我遵循的基本步骤:
- 将不属于单词的所有 Unicode 字符 (>= 128) 替换为 space 字符。
- (可选)用更通用的字符替换特定字符。例如,
ē
、è
和é
都可以替换为e
(如果需要这种通用搜索)。这不是必需的,但如果你不这样做,那么搜索é
将只会 return 带有é
的文档,而搜索e
只会 [=45] =] 带有e
的文档(而不是é
)。 - 使用在步骤 1 和 2 中创建的修改后的文本填充虚拟 FTS table。
- 使用未修改的文本填充您的正常 table。当然,架构和文档数量必须与您创建 FTS 时相同 table。
- Link 虚拟 FTS table 与您的普通文本 table/column 使用外部内容 table 这样您就不会存储修改后文本的副本,仅从该文本创建的文档 ID。
请阅读
如果您需要更多详细信息,请在下面发表评论。