Android 中的 Sqlite 全文搜索对非英语字符的 Unicode 支持

2024-05-02

滚动到末尾以跳过说明。

背景

在我的 Android 应用程序中,我想使用非英语 Unicode 文本字符串来搜索存储在 SQLite 数据库中的文本文档/字段中的匹配项。我了解到(所以我认为)我需要做的是实施一个使用 fts3/fts4 进行全文搜索 http://www.sqlite.org/fts3.html#section_1,这就是我这几天一直在努力学习的内容。 Android 支持 FTS,如文档所示存储和搜索数据 http://developer.android.com/training/search/search.html并在博客文章中Android 快速提示:使用 SQLite FTS 表 http://blog.andresteingress.com/2011/09/30/android-quick-tip-using-sqlite-fts-tables/.

Problem

一切看起来都不错,但后来我读了 2012 年 3 月的博客文章Android 上 SQLite 全文搜索的遗憾现状 http://kmansoft.com/2012/03/17/the-sorry-state-of-sqlite-full-text-search-on-android/,其中说

建立全文搜索索引的第一步是分解 将文本内容转换为单词,也称为标记。那么这些令牌就是 输入一个特殊的索引,让 SQLite 执行速度非常快 基于一个标记(或一组标记)的搜索。

SQLite 有两个内置的分词器 http://www.sqlite.org/fts3.html#tokenizer,并且他们都只考虑 token 由 US ASCII 字符组成。所有其他非 US ASCII 字符 被视为空白。

之后我还发现这个 StackOverflow 答案 https://stackoverflow.com/a/17399384/3681880 by @CL. https://stackoverflow.com/users/11654/cl(根据标签和声誉,他似乎是 SQLite 专家)回答有关将越南语字母与不同变音符号匹配的问题:

您必须使用可以处理 Unicode 的分词器创建 FTS 表 字符,即 ICU 或 UNICODE61。

请注意,这些标记器可能不适用于所有 Android 版本,并且 Android API 不公开任何 用于添加用户定义的标记器的函数。

这个2011年的答案 https://stackoverflow.com/a/8183890/3681880似乎证实 Android 不支持超出两个基本的标记器simple and porter ones.

现在是2015年了,这种情况有什么更新吗?我需要为使用我的应用程序的每个人提供全文搜索支持,而不仅仅是拥有新手机的人(即使最新的 Android 版本现在确实支持它)。

潜在的部分解决方案?

我很难相信 FTS 根本不能与 Unicode 一起使用。这文档 http://www.sqlite.org/fts3.html#tokenizer为了simple分词器说

术语是符合条件的字符的连续序列,其中符合条件的 字符均为字母数字字符和所有字符 Unicode 代码点值大于或等于 128。所有其他 将文档拆分为术语时,字符将被丢弃。他们的 唯一的贡献是分离相邻的术语。(强调已添加)

这给了我希望,即使不支持大写和变音符号(以及具有不同 Unicode 代码点的各种其他等效字母形式)之类的内容,Android 中仍然可以支持一些基本的 Unicode 功能。

我的主要问题

如果我仅使用以空格分隔的文字 Unicode 字符串标记,我可以在 Android 中将 SQLite FTS 与非英语 Unicode 文本(代码点 > 128)一起使用吗? (也就是说,我正在搜索文本中出现的确切字符串。)

Updates

  • The unicode61 分词器 https://www.sqlite.org/fts3.html#unicode61在 SQLite 版本 3.7.13 中可用。该分词器支持“完整的 unicode 大小写折叠”和“识别 unicode 空格和标点字符”。Android Lollipop(API 20+)使用 SQLite 3.8 https://stackoverflow.com/questions/2421189/version-of-sqlite-used-in-android/4377116#4377116.

补充答案

我最终按照 @CL 的建议进行了操作,并成功地使用 Unicode 实现了全文搜索。这些是我遵循的基本步骤:

  1. 将不属于单词一部分的所有 Unicode 字符 (>= 128) 替换为空格字符。
  2. (可选)用更通用的字符替换特定字符。例如,ē, è, and é都可以替换为e(如果需要这种广义搜索)。这不是必需的,但如果您不这样做,则搜索é只会返回带有以下内容的文档é,并寻找e只会返回带有以下内容的文档e(并不是é).
  3. 使用步骤 1 和 2 中创建的修改文本填充虚拟 FTS 表。
  4. 使用未修改的文本填充普通表。当然,架构和文档数量必须与创建 FTS 表时相同。
  5. 使用外部内容表将虚拟 FTS 表与普通文本表/列链接起来,这样您就不会存储修改后的文本的副本,而只会存储从该文本创建的文档 ID。

请阅读Android 中的全文搜索示例 https://stackoverflow.com/a/29926430/3681880有关如何创建 FTS 表并将其链接到普通表的说明。这花了很长时间才弄清楚,但最终它甚至可以对大量文档进行非常快速的全文搜索。

如果您需要更多详细信息,请在下面发表评论。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Android 中的 Sqlite 全文搜索对非英语字符的 Unicode 支持 的相关文章

随机推荐

  • React Hooks:无法分配给只读属性

    我正在尝试更新使用 React createElement 创建的对象 我试图更新的属性是particleCopy props style top 下面是我的代码 import React useState from react impor
  • 停止将 Chromium 放在前面

    我的测试运行 Puppeteerheadless false模式并打开几个选项卡 如果我在另一个应用程序窗口中 每当它打开一个新选项卡时 它会将 Chromium 聚焦到视图中 这很烦人 有什么办法让它在后台运行吗 我使用的是 macOS
  • 显示函数的完全限定名称

    include
  • 查找最近n天内的所有文档

    My daily集合包含以下文档 date ISODate 2013 01 03T00 00 00Z vid ED san 7046 25 izm 1243 96 date ISODate 2013 01 03T00 00 00Z vid
  • Java + JNA:找不到指定的过程

    我正在尝试使用 Visual Studio 创建一个 dll 文件并在 java 项目中使用 访问它 该库似乎已加载 但总是抛出相同的异常 线程 main 中出现异常 java lang UnsatisfiedLinkError 查找函数
  • 有没有办法在 Visual Studio 项目中创建用户特定的预/后构建事件?

    我目前正在项目中使用构建后事件将程序集复制到另一个目录以进行调试 这是我的机器本地的 仅用于调试目的 所以我更愿意将它放在 中 csproj user文件而不是 csproj文件 我尝试从 复制负责的元素 csproj到 csproj us
  • 方法链接的优点和缺点以及用对象本身替换所有 void 返回参数的可能性

    我最感兴趣的是Java 但我认为这是一个普遍的问题 最近我一直在使用 Arquillian 框架 ShrinkWrap 使用了大量的方法链 方法链的其他示例是以下方法StringBuilder StringBuffer 使用这种方法有明显的
  • onchange 选择框

    假设我们有 2 个不同的选择框 具有相同数量的选项
  • 如何在 jQuery 中使用其中心作为参考点来缩小 div?

    我有以下 div div style margin left 0px height 100px width 100px background color red div 我想使用 jQueryanimate 将 div 缩小到其大小的一半
  • C:epoll和多线程

    我需要创建专门的 HTTP 服务器 为此我计划使用 epoll sycall 但我想利用多个处理器 核心 但我无法提出架构解决方案 ATM我的想法如下 使用自己的epoll描述符创建多个线程 主线程接受连接并将它们分配给线程epoll 但还
  • Java 数组返回奇怪的输出[重复]

    这个问题在这里已经有答案了 我正在为家庭作业问题创建一个方法 该方法返回数组中的最高值 我正在使用一个 for循环将数字输入到数组中 输入代码如下所示 int array new int n for i 0 i
  • 如何在 g++ 中使用不同的 STL

    我想对 g 使用不同的 STL 而不是其默认的 libstdc 做到这一点最简单的方法是什么 我发现 nostdinc 标志禁止 g 查找其 STL 标头 但这只是编译时的事情 它仍然会使 g 链接到它自己的 STL 所以我需要找到一种方法
  • 将二进制文件转换为图像

    我需要找到一种将二进制文件转换为图像的快速方法 二进制文件由 N 个NN 矩阵 我想将 0 与一种颜色关联 将 1 与另一种颜色关联 我需要对超过 1000 个二进制文件执行此操作 如果可能的话 我想避免使用 MatLab 有没有任何工具
  • UITextView突出显示的文本颜色或类似的选项?

    我有一个习惯UITableViewCell with a UILabel and a UITextView in it 我希望当用户突出显示时 这两个文本都显示为白色UITableViewCell 显然设置起来非常简单highlighted
  • 在 C# 中快速加载/读取 TIFF 文件

    我正在编写一个处理 TIFF 图像的 C 应用程序 主要是显示文件 重新排序页面 删除页面 分割多页图像 将单个图像合并为一个多页图像等 我们处理的大多数图像都较小 无论是文件大小还是页码 但也有一些较大的图像 显示图像时 我们需要将多页
  • SSRS 导出到 Excel 创建附加列

    我有一个 SSRS 报告 当我导出到 Excel 时 在 Excel 中查看时会创建不需要的列 确保不创建额外列的最佳方法是什么 我尝试将表行的位置设置为0in 0in但这并没有解决问题 随附的屏幕截图是报告在 Visual Studio
  • 使用 decltype() 声明函数签名

    是否可以声明一个函数bar与函数具有相同的签名foo int foo int a return 0 decltype foo bar return 1 imaginary syntax 我认为这同样适用于 typedef 和别名 您可以使用
  • Oracle SQL:从表中选择数据和分区名称并截断分区

    这是一个由两部分组成的问题 1 是否可以根据数据所在的分区使用 select 语句检索其名称ROWID或者其他一些标识符 eg SELECT DATA ID CATEGORY VALUE PARTITION NAME FROM MYTABL
  • Spring - 捕获bean创建异常

    我想在我的代码中捕获 bean 实例化异常 我有什么选择 一种方法是使用基于 Java 的容器配置 Configuration public class AppConfig Bean public SomeBean someBean try
  • Android 中的 Sqlite 全文搜索对非英语字符的 Unicode 支持

    滚动到末尾以跳过说明 背景 在我的 Android 应用程序中 我想使用非英语 Unicode 文本字符串来搜索存储在 SQLite 数据库中的文本文档 字段中的匹配项 我了解到 所以我认为 我需要做的是实施一个使用 fts3 fts4 进