一年前开发 simple 分词器,实现了微信在两篇文章中描述的,基于 SQLite 支持中文和拼音的搜索方案。具体背景参见这篇文章。项目发布后受到了一些朋友的关注,后续也发布了一些改进,提升了项目易用性。

最近重新体验微信客户端搜索功能,发现对于中文的搜索已经不是基于单字命中,而是更精准的基于词组。比如搜索“法国”,之前如果句子中有“法”和“国”两个字时也会命中,所以如果一句话里包含“国法”就会被命中,但是这跟“法国”没有任何关系。

本文描述对 simple 分词器添加的基于词组命中的实现,从而实现更好的查找效果。另外本文也会基于之前在 issue 中大家提到的问题,提供一个怎么使用 SQLite FTS 表的建议。

背景

先简单回顾一下之前的实现,因为结巴分词只跟中文有关,所以本文会略去拼音的部分。

搜索主要分为两部分,建立索引和命中索引。为了实现中文的搜索,我们先把句子按照单字拆分,按照单字建立索引;然后对于用户的输入,也同样按照单字拆分,这样 query 就能命中索引了。为了支持词组搜索,再按照单字拆分就很难满足需求了,所以可以考虑的方案是要么改索引,要么改 query。如果改索引的话会有一些问题,比如如果用户就输入了一个字比如“国”,但是我们建索引的时候把“法国”放到了一起,那“国”字就命中不了了,所以最好是保持单字索引不变,通过改写 query 来达到检索词组的效果。

实现

simple 分词器之前提供了一个 simple_query() 函数来帮助用户生成 query,我们也可以加一个新的函数来实现词组的功能。经过简单的调研,我们发现 cppjieba 用 C++ 实现了结巴分词的功能,很适用于我们的需求。

所以我实现了一个新的函数叫做 jieba_query() ,它的使用方式跟 simple_query() 一样,内部实现时,我们会先使用 cppjieba 对输入进行分词,再根据分词的结果构建 SQLite3 能理解的 query ,从而实现了词组匹配的功能。具体的逻辑可以参考 这里 。对于不需要结巴分词功能的用户,可以在编译的时候使用 -DSIMPLE_WITH_JIEBA=OFF 关闭结巴分词的功能,这样能减少编译文件的大小,方便客户端对文件大小敏感的场景使用。

使用

本文想着重介绍一下 SQLite3 FTS5 功能使用的问题,这些问题都是有朋友在项目的 issue 中提到过的,都是非常好的问题,但是也说明有不少人对怎么使用 FTS 表不太清楚,希望本文能解决一些疑惑。

首先第一点,FTS5 表虽然是一个虚拟表,提供了全文搜索的功能,但是它整体还是跳不出 SQL 的范畴,所以其实很多用法和其他 SQL 表是一样的,当然它也跳不出 SQL 的限制。比如有一个 issue 问如果表中有多列的时候,能不能检索全表,但是只返回命中的那些列?答案是不行的,因为按照 SQL 的语法规则,SELECT 语句后面必须显示说明你想要 SELECT 哪些列,所以结果列是必须用户指定的,如果我们像知道哪些列命中了,只能通过其他一些手段,感兴趣的朋友可以看这个 issue36。

另外 simple 分词器提供了不少额外的功能,比如 simple_query() 和 simple_highlight() 等辅助函数,但是它并不影响我们使用原有 FTS5 的功能,比如如果想按照相关度排序,FTS5 自带的 order by rank 功能还是可以继续可以使用,也就是说 FTS5 页面 提供的所有功能都是可以和 simple 分词器一起使用的。

最后也是最重要的一个问题,FTS5 表到底该怎么用?有一个 issue26 提到的问题非常好,我把它放到这里:

《微信全文搜索优化之路》一文中针对索引表的介绍,我对索引有几个问题想请教一下:

  1. 业务表是正常的程序的数据表,还要再为了全文搜索再多建立一份索引表,是吗?我直接将我的业务数据表在创建的时候按虚表建立行吗?(例如create virtual table tablename using fts5(列名1,列名2,tokenize = ‘simple’))
  2. 如果再多建立一份索引表,那是不是每一个业务表和对应的索引表的表字段是完全相同?
  3. 如果再多建立一份索引表,那数据库的大小是不是加倍了,尤其是把文件或图片影片存入数据库的情况(BLOB类型)?
  4. 原文中【为了解决业务变化而带来的表结构修改问题,微信把业务属性数字化】,这也是我想要的,能否帮助贴下原文中提到的【索引表-IndexTable】和【数据表-MetaTable】的建表语句?

核心的问题是:想让表数据支持全文搜索,需要把数据复制一份吗?这样会不会导致数据库膨胀?在用户的手机上我们可不想占用太多无谓的空间。

externel content table

其实这个问题在 FTS5 的官方文档中已经给出了解决方案那就是 externel content table,大家也可以参考 这篇文章 。

它的意思是我们可以建一张普通表,然后再建一张 FTS5 表来支持全文索引,这张虚拟表本身不会存储真实的数据,如果 SELECT 语句用到具体的内容,都会通过关联关系去原表获取,这样就不存在数据重复的问题了。但是这里就会涉及到数据一致性的问题,怎么保证原表的数据和索引表是一致的呢?通过 trigger 也就是触发器来实现:对于原表的增删改,都会通过触发器同步到 FTS 表。这样基本上就完美解决了上面用户的问题。

可能有人会问为什么不直接用 FTS5 表呢?这样普通表就不用了,也省了触发器的逻辑。原因是 FTS 表提供了全文索引的能力,但是它也有限制,对于基于 ID 或者其他普通索引的请求它是不支持的,如果我们想有一个时间列并且基于时间列索引排序,FTS表就不行,还是需要普通表。通过普通表和 FTS 表结合的方案,我们就能同时使用两者的能力。

微信的方案

需要注意的是,微信并没有使用上面提到的方案,而是单独建了一张打平的索引表,把所有需要全文索引的数据放到一张单独的表里面,再通过外键关联到具体的业务去。这样的好处在微信的文章中有所提及,主要是其他关联的表结构变更的时候,FTS 表不用动,这样很容易添加想要搜索的字段,只需把该字段写入 FTS 表及关联关系的表就行,表结构见下图:

个人觉得对于微信这个复杂度的业务,可以考虑这个方案,毕竟需要搜索的信息非常多,这样方便各个业务复用搜索能力。但是对于大部分的业务,用 external content table 可能是更简单的方案,毕竟在数据写入和读取的时候都更快更方便,微信的方案在数据操作流程上会复杂不少,需要逻辑上做更多的封装。

总结

上面主要介绍了 simple 分词器最新的功能,基于结巴分词实现基于词组的搜索功能,实现更精准的匹配。另外也介绍了在实际项目中使用 FTS 表的方案,希望对大家有所助益。

Reference

  • Simple 分词器: https://github.com/wangfenjin/simple
  • sqlite 官方文档:https://www.sqlite.org/fts5.html
  • 微信全文搜索优化之路:https://cloud.tencent.com/developer/article/1006159
  • 微信移动端的全文检索多音字问题解决方案:https://cloud.tencent.com/developer/article/1198371
  • Simple: 一个支持中文和拼音搜索的 sqlite fts5插件:https://www.wangfenjin.com/posts/simple-tokenizer/
  • Full Text Search With Sqlite SQLite:https://kimsereylam.com/sqlite/2020/03/06/full-text-search-with-sqlite.html

Simple: SQLite3 结巴分词插件相关推荐

  1. mysql使用结巴语句_结巴分词 java 高性能实现,是 huaban jieba 速度的 2倍

    Segment Segment 是基于结巴分词词库实现的更加灵活,高性能的 java 分词实现. 创作目的 分词是做 NLP 相关工作,非常基础的一项功能. jieba-analysis 作为一款非常 ...

  2. python结巴分词代码_python结巴分词SEO的应用详解

    本帖最后由 为人生而奋斗 于 2019-10-15 16:19 编辑 结巴分词在SEO中可以应用于分析/提取文章关键词.关键词归类.标题重写.文章伪原创等等方面,用处非常多. 具体结巴分词项目:htt ...

  3. ElasticSearch6.2.2 ansj分词插件使用和其它比较

    大纲 一.elasticsearch6 ansj分词简介 二.elasticsearch6 ansj分词安装 三.elasticsearch6 ansj分词配置 四.elasticsearch6 an ...

  4. mysql 中文搜索插件_支持中文的MySQL 5.1+ 全文检索分词插件

    经过不停的尝试和努力,以最新的 mysql 5.1.11-beta 为基础,制作的分词插件已经测试成功,现在发布如下. 由于 mysql 5.1.x 本身的架构作了修改,所以增加分词直接以插件形式方式 ...

  5. 结巴分词和自然语言处理HanLP处理手记

    手记实用系列文章: 1 结巴分词和自然语言处理HanLP处理手记 2 Python中文语料批量预处理手记 3 自然语言处理手记 4 Python中调用自然语言处理工具HanLP手记 5 Python中 ...

  6. 基于 Ansj 的 elasticsearch 2.3.1 中文分词插件

    前言 这是一个elasticsearch的中文分词插件,基于Ansj中文分词.发起者Onni大神. 2.3.1插件安装 进入Elasticsearch目录运行如下命令 进入es目录执行如下命令 ./b ...

  7. Python 结巴分词(1)分词

    利用结巴分词来进行词频的统计,并输出到文件中. 结巴分词github地址:结巴分词 结巴分词的特点: 支持三种分词模式: 精确模式,试图将句子最精确地切开,适合文本分析: 全模式,把句子中所有的可以成 ...

  8. 结巴分词jieba添加自定义词典

    结巴分词添加自定义词典,有时候很有必要.比如下面这段话: test_text = """ 我们的健康码也是绿色的,这凭什么就限制我们的就医!""&qu ...

  9. elasticsearch6.2.2安装中文分词插件IK analyzer

    elasticsearch6.2.2安装中文分词插件IK analyzer 哎,装了一下午的ik终于装上了,发现自己真的是非常笨了,并且es重启过程中遇到了很多的问题,下面我将手把手教大家如何安装ik ...

最新文章

  1. java 多线程 信号_Java多线程——Semaphore信号灯
  2. 【c语言】打印*型金字塔
  3. java lock代码写法_java Lock接口详解及实例代码
  4. 让大数据分析更简单,4步教你玩转MongoDB BI Connector
  5. 探求数据仓库关键环节ETL的本质
  6. BOSS直聘发起“逆行者先行”招聘专场:优先录取抗疫志愿者
  7. 有没有办法在Android上运行Python?
  8. RpcOrtho failed: An unknown process erroroccurred.
  9. 直播礼物特效新格式-Pag格式
  10. bootstrap菜单html,Bootstrap实现下拉菜单效果
  11. 【转载】CPU的内部架构和工作原理
  12. CMD命令创建文件夹快捷方式
  13. 小程序二维码和小程序带参数二维码生成
  14. 《红楼梦》的方位观念
  15. (数论)[SDOI2008]沙拉公主的题目描述
  16. 00无人机简介以及课程介绍2020-07-03
  17. 微信小程序系列——js遍历数组,微信小程序数组的遍历,forEach
  18. 鸿蒙最新功能及承载设备详解:HarmonyOS 2及华为全场景新品发布会全纪录
  19. 服务器生成镜像文件,云服务器 生成镜像
  20. mysql连接 xorm_go xorm连接数据库

热门文章

  1. 华为android5.1版本,华为P10国行版搭载的EMUI5.1怎么样?
  2. ctfshow web80-88
  3. 吴恩达神经网络与深度学习——浅层神经网络
  4. 都市丽人荣获多项大奖情感营销触达消费者心流
  5. matlab 膨胀 结构元,图像形态学膨胀 结构元素
  6. C语言-基础知识练习习题1
  7. 计算机外文参考文献2018,2018年英文参考文献格式-推荐word版 (5页)
  8. 关于CH375芯片的简介以及其与51单片机的连接
  9. 从JSON进化到BSON
  10. 集成电路开发及应用-设计部分专栏目录