首页 > 数据库 > 文章详情

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




作者:黑夜路人(heiyeluren)

时间:2021/1/13



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

比如说,有一个问题场景是这样的:

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


大概是这样的:



使用场景:

【输入“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. 排序后输出:把上面对应权重结果列表排序输出结果,返回给调用应用。


开源分词推荐:结巴分词、LibMMSeg、SCWS分词、IK分词

相关性计算算法:TF-IDF算法



【方案2:使用MySQL实现全文检索引擎】

推荐指数:☆☆☆

编程语言:无限制

适用场景:数据量中等,比如在千万规模,然后是MySQL为主的存储结构,可以考虑如下方式。


实现方式1:MySQL 5.7 + Ngram分词器

老版本MySQL的FULLINDEX是针对英文的全文检索,无法检索处理中文;在新版本之后,有新的分词算法,采用MySQL 5.7.22之后版本自带的Ngram全文解析器进行分词,采用SQL语句的MATCH...AGAINST语句完成全文检索,类似于:

SELECT * FROM articlesWHERE MATCH (title,body)AGAINST ('全文 检索' IN NATURAL LANGUAGE MODE);

不足:Ngram分词器的整个偏机械,没法做好的语义处理,不过也能够兼容一些比如MySQL里查找SQL这种场景。



实现方式2:采用MySQL+IK分词器

在MySQL5.6以下,只有MyISAM引擎支持全文检索。在MySQL5.6以上Innodb引擎也提供支持全文检索。相应字段需要建立FULLTEXT索引。

MySQL5.7.6以下只支持英文全文索引,不支持中文全文索引,需要利用IK分词器把中文段落拆分成单词。对比方案1来说,分词更准确,并且不需要依赖于ES这种外部的解决方案。

不足:性能不高,并且只能针对小数据量。


实现方式3:MySQL+Sphinx引擎

主要是MySQL结合开源的检索引擎来实现;使用MySQL + Sphinx 方式做全文检索,使用mysql作为数据源,使用sphinx作为分词和存储检索引擎。

不足:相对来说安装部署麻烦一点,需要依赖于第三方引擎。



【方案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秒,没法做复杂的权重排序处理。



【方案4:采用Lucene/Elasticsearch或Xunsearch/Solr服务】

推荐指数:☆☆☆☆

编程语言:无限制

适用场景:数据量比较大,比如在千万或者亿级别的数据量,自己不想做开发,直接用现成的


实现方法:Elasticsearch是一个常用的日志或大数据存储的开源搜索引擎,底层检索引擎主要是采用Lucene进行的实现,所以二者可以单独使用,效果类似,可以自己本地搭建,安装配置稍微有点复杂。如果想要省事,可以使用第三方服务(比如阿里云)直接灌入数据,然后远程拉取数据结果等方式。(整个方案适合数据量偏大的场景)


不足:安装部署麻烦,需要灌数据再查询,还依赖于外部服务。


其他可以参考的服务包括:Solr、Xunsearch、Lucene、第三方搜索云服务(阿里云、腾讯云等)


【方案5:其他开源的全文检索引擎或者检索库】

推荐指数:☆☆

编程语言:Golang/C/C++/Java

适用场景:除了常规著名的ES/Lucene/Solr等等搜索引擎,也还有很多其他不错的开源搜索引擎可以参考学习使用,看是否适合自己的业务场景。

不足:部分需要有二次开发或者很好的编译部署能力,部分引擎也需要考虑更新维护情况。


经典全文搜索引擎:Xapian(C++开发)

腾讯微信全文检索引擎:wwsearch (C/C++开发)

北大搜索引擎TSE:LBTSE(C/C++开发)

Redis搜索引擎:RediSearch (C开发)

Go分布式全文搜索引擎:Riot (Go开发)

悟空搜索引擎:Wukong(Go开发)

单机搜索引擎:nsearch(Go开发)

倒排压缩全文搜素引擎:Zettair (C开发)



【方案6:自己纯原生编程实现全文检索服务】

推荐指数:☆☆

编程语言:Java/Python/Golang/C++

适用场景:数据量看业务规模,推荐十万~百万规模级别的数据量,想要有一个自主开发的适用自己业务的全文检索引擎,可以考虑这个方案。

不足:需要自己开发很多程序代码,性能、可靠性等完全依赖于自己的实现技术。


1. 全文检索引擎主要服务构成


a. 数据接口服务:包含输入数据、查询数据的接口,可能提供tcp或者http类的服务接口,能够接受大规模并发请求,会做一些查询结果的缓存工作,不用直接请求查询服务可以直接返回结果等等一些工程层优化。

b. 数据存储服务:包含输入数据后的数据基本归一化处理、数据的基本分词权重计算、按照倒排表/hashmap/树 结构存储索引和对应原始内容关系,最终生成对应数据文件和索引文件。

c. 数据检索服务:包含输入查询词语的分词、权重相关性计算(tf-idf/bm25)、拉取对应的索引和最终数据,按照权重后排序输出,包含核心的关键词和对应实体文本内容。

d. 按照自己业务情况,还可以增加其他服务,比如数据抓取,数据清洗等等。


2. 主要涉及到的算法和技术


a. 分词算法:主要分为传统机械分词和机器学习分词技术,如果应用场景简单,可以采用传统机械分词技术,简单有效,也有涉及到更高级的深入理解语义的自然语言处理技术NLP。(偏机械分词算法包括 正向最大匹配、逆向最大匹配、Ngram元匹配、CRF条件随机场、词频统计 等等算法,有很多开源库可以直接用)


b. 关键词-文本关联结构和算法:一般主要使用的是倒排表的方法,把相关搜索关键词与最终文本相互关联的技术。(有很多开源实现方案可以直接用)


c. 词库存储结构和算法:一般词库存储采用hash或者是trie-tree(字典树/前缀树)的算法实现(有很多开源实现方案可以直接用)


d. 关键词-文本权重相关性算法:tf-idf模型 / bm25算法,主要是通过词频等方式来计算一个关键词在一个文档里的整个相关性计算。(这个对搜索结果至关重要,实现算法众多,只是介绍最常用最简单的,ES中也是支持TF-IDF和BM25算法)


3.  推荐全文检索相关学习书籍(如果想深入学习的话)

《信息检索导论》

《搜索引擎——原理技术与系统》

《这就是搜索引擎:搜索引擎技术详解》

《自制搜索引擎》

《自己动手写分布式搜索引擎》

《深入理解ElasticSearch》




备注说明:

上面文档里很多延伸阅读的参考链接,因为公众号限制无法点击链接,建议“阅读原文”深入访问这些链接,了解更多信息。






作者简介:


黑夜路人(heiyeluren),目前就职于学而思网校,系学而思网校技术委员会主席;CSDN博客技术专家,互联网后端技术架构师,多年PHP/C/C++/Golang开发经验,LNMP技术栈/分布式/高并发等技术爱好者,国内开源社区和开源技术布道者。



 

个人博客:http://blog.csdn.net/heiyeshuwu

新浪微博:http://weibo.com/heiyeluren

微信公众号:黑夜路人


相关文章分享