支持模糊匹配站内全文检索的技术方案

转自黑夜路人博客

Posted by hughnian on January 18, 2021

全文检索/全文搜索的问题场景:

比如说,有一个问题场景是这样的:
在计算机课程培训体系中,现在有个需求是实现根据用户输入关键字,搜索课程名称和课程简介进行匹配度计算的场景的问题,初步数据量不大。

大概是这样的:

使用场景:

【输入“mysql”关键字,可以匹配这些】:

mysql引擎innodb介绍 (完全匹配)

mysql介绍 (完全匹配)

正确使用MySQL(完全匹配)

sql优化(部分匹配,召回)

sq(放弃)

全文检索技术应用场景,还有比如搜索微信公众号的文章:

这些场景分析下来,这个是一个典型的依赖输入一个关键词,然后通过模糊匹配,把这个相关的文档或者文本内容做对应检索,按照权重输出结果的问题,这个就是典型的“全文检索/全文搜索”的一个技术问题场景,跟我们日常使用的站内搜索、全网索索本质需求是一样的,只是应用场景简单一些,因为数据量不大,所以对应解决方案也比较多一些,通过技术梳理,分享如下解决方案。

【方案1:纯自己编码实现简单全文检索方案】
推荐指数:☆☆☆☆
编程语言:Java/Golang/C++/Python
适用场景:数据量比较小,比如在十万级别,但是一般的KMP等字符串匹配算法无法满足,自己需要练练手快速实现全文检索。

  • a. 存储文档:把对应500标题构建成为一个字符串列表(可以是map/set之类容器结构,放到内存里,通过迭代器可以遍历)

  • b. 文档分词建立倒排:把这些标题进行分词(采用开源分词方法)存储到一个分词索引结构里,可以是倒排表或者就是一个粗暴的hashmap。(存储关系是词语与上面字符串组之间的关联关系)

  • c. 用户检索处理:用户输入词汇以后进行分词(采用开源分词库)检索b中是否有对应的词汇,如果有,按照权重把对应列表排序拉出来,再映射到a中的字符串列表提取出来。(这一步骤可以直接简单拉取可以,也可以采用 tf-idf 或者 bm25 算法计算方式,如果想偷懒,不采用这么复杂的方法也行)

  • d. 排序后输出:把上面对应权重结果列表排序输出结果,返回给调用应用。

开源推荐:
结巴分词(推荐):https://github.com/fxsjy/jieba
结巴分词使用:https://www.jianshu.com/p/883c2171cdb5
LibMMSeg:https://www.oschina.net/p/libmmseg
SCWS分词:http://www.xunsearch.com/scws/index.php
TF-IDF算法:https://blog.csdn.net/zhb_bupt/article/details/40985831

【方案2:使用MySQL实现全文检索引擎】
推荐指数:☆☆☆
编程语言:无限制
适用场景:数据量中等,比如在千万规模,然后是MySQL为主的存储结构,可以考虑如下方式。

实现方式1:MySQL 5.7 + Ngram分词器
老版本MySQL的FULLINDEX是针对英文的全文检索,无法检索处理中文;在新版本之后,有新的分词算法,采用MySQL 5.7.22之后版本自带的Ngram全文解析器进行分词,采用SQL语句的MATCH…AGAINST语句完成全文检索。
不足:Ngram分词器的整个偏机械,没法做好的语义处理,不过也能够兼容一些比如MySQL里查找SQL这种场景。
参考文档1:https://www.cnblogs.com/xuey/p/11631102.html
参考文档2:https://blog.csdn.net/weixin_51686373/article/details/109773911

实现方式2:采用MySQL+IK分词器
在MySQL5.6以下,只有MyISAM引擎支持全文检索。在MySQL5.6以上Innodb引擎也提供支持全文检索。相应字段需要建立FULLTEXT索引。
MySQL5.7.6以下只支持英文全文索引,不支持中文全文索引,需要利用IK分词器把中文段落拆分成单词。对比方案1来说,分词更准确,并且不需要依赖于ES这种外部的解决方案。
不足:性能不高,并且只能针对小数据量。

实现方式3:MySQL+Sphinx引擎
主要是MySQL结合开源的检索引擎来实现;使用MySQL + Sphinx 方式做全文检索,使用mysql作为数据源,使用sphinx作为分词和存储检索引擎。
不足:相对来说安装部署麻烦一点,需要依赖于第三方引擎。
参考文档:https://blog.csdn.net/socho/article/details/52251177

【方案3:用MongoDB的全文检索引擎】
推荐指数:☆☆
编程语言:无限制
适用场景:数据量比较小,并且自己存储是采用MongoDB的方式,不需要做更多数据转存和处理的场景。
实现方式:
高版本的MongoDB 3.4版本以后支持部分中文检索,主要方式是Mongodb针对一个doc的字段进行创建全文检索索引,然后采用find来进行全文索引查找,可以按照相似度排序。
实现过程是用 db.create_index([("metaDataList.title",pymongo.TEXT)]) 建text全文索引,然后通过 db.find({ "$text": { "$search": "关键词" }},{ "score": { "$meta": "textScore" } }) 进行检索,可以通过textScore得到权重值后排序输出。
不足:中文支持不是很好,凑合用,数据量不要太大,不然性能会比较差,千万级以上数据查询时间可能会大于10秒,没法做复杂的权重排序处理。
参考文档1:https://www.jianshu.com/p/a3d763b29553
参考文档2:https://docs.mongoing.com/indexes/text-indexes

【方案4:采用Lucene/Elasticsearch或Xunsearch/Solr等第三方服务实现全文检索】
推荐指数:☆☆☆☆
编程语言:无限制
适用场景:数据量比较大,比如在千万或者亿级别的数据量,自己不想做开发,直接用现成的
实现方法:Elasticsearch是一个常用的日志或大数据存储的开源搜索引擎,底层检索引擎主要是采用Lucene进行的实现,所以二者可以单独使用,效果类似,可以自己本地搭建,安装配置稍微有点复杂。如果想要省事,可以使用第三方服务(比如阿里云)直接灌入数据,然后远程拉取数据结果等方式。(整个方案适合数据量偏大的场景)
不足:安装部署麻烦,需要灌数据再查询,还依赖于外部服务。
Lucene全文检索1:https://blog.csdn.net/zhang18024666607/article/details/78216635
Lucene全文检索2:https://zhuanlan.zhihu.com/p/73875797
ES入门教程:http://www.ruanyifeng.com/blog/2017/08/elasticsearch.html
ES全文检索:https://www.cnblogs.com/softidea/p/6119362.html
阿里云ES服务:https://www.aliyun.com/product/bigdata/product/elasticsearch
阿里云检索服务:{:target=”_blank”}https://www.aliyun.com/product/opensearch
Xunsearch检索服务:http://xunsearch.com
Solr学习使用:https://www.cnblogs.com/yanduanduan/p/7344667.html

【方案5:其他开源的全文检索引擎或者检索库】
推荐指数:☆☆
编程语言:Golang/C/C++/Java
适用场景:除了常规著名的ES/Lucene/Solr等等搜索引擎,也还有很多其他不错的开源搜索引擎可以参考学习使用,看是否适合自己的业务场景。
不足:部分需要有二次开发或者很好的编译部署能力,部分引擎也需要考虑更新维护情况。
经典全文搜索引擎:Xapian(C++开发, https://xapian.org
腾讯微信全文检索引擎:wwsearch (C/C++开发,https://github.com/Tencent/wwsearch
北大搜索引擎TSE:LBTSE(C/C++开发,https://gitee.com/lewsn2008/LBTSE
Redis搜索引擎:RediSearch (C开发,https://github.com/RediSearch/RediSearch
Go分布式全文搜索引擎:Riot (Go开发,https://gitee.com/veni0/riot
悟空搜索引擎:Wukong(Go开发,https://github.com/huichen/wukong
单机搜索引擎:nsearch(Go开发,https://github.com/HughNian/nsearch,✌这个项目被大佬推荐了,我会维护好这个项目)
倒排压缩全文搜素引擎:Zettair (C开发,http://www.seg.rmit.edu.au/zettair
其他搜索引擎推荐:https://blog.csdn.net/xum2008/article/details/8740063

【方案6:自己纯原生编程实现全文检索服务】
推荐指数:☆☆
编程语言:Java/Python/Golang/C++
适用场景:数据量看业务规模,推荐十万~百万规模级别的数据量,想要有一个自主开发的适用自己业务的全文检索引擎,可以考虑这个方案。
不足:需要自己开发很多程序代码,性能、可靠性等完全依赖于自己的实现技术。

  1. 全文检索引擎主要服务构成
    • a. 数据接口服务:包含输入数据、查询数据的接口,可能提供tcp或者http类的服务接口,能够接受大规模并发请求,会做一些查询结果的缓存工作,不用直接请求查询服务可以直接返回结果等等一些工程层优化。
    • b. 数据存储服务:包含输入数据后的数据基本归一化处理、数据的基本分词权重计算、按照倒排表/hashmap/树 结构存储索引和对应原始内容关系,最终生成对应数据文件和索引文件。
    • c. 数据检索服务:包含输入查询词语的分词、权重相关性计算(tf-idf/bm25)、拉取对应的索引和最终数据,按照权重后排序输出,包含核心的关键词和对应实体文本内容。
    • d. 按照自己业务情况,还可以增加其他服务,比如数据抓取,数据清洗等等。
  2. 主要涉及到的算法和技术
  3. 推荐全文检索相关学习书籍(如果想深入学习的话)
    《信息检索导论》:https://item.jd.com/12554083.html
    《搜索引擎——原理技术与系统》:https://item.jd.com/12496373.html
    《这就是搜索引擎:搜索引擎技术详解》:http://jxz1.j9p.com/pc/zjsssyq.zip
    《自制搜索引擎》:https://item.jd.com/11837411.html
    《自己动手写分布式搜索引擎》https://item.jd.com/12202453.html
    《深入理解ElasticSearch》:https://item.jd.com/12617323.html

转自黑夜路人博客,原文地址 https://blog.csdn.net/heiyeshuwu/article/details/112582583