本篇主要讲解倒排索引的基本原理以及ES经常使用的几种分词器介绍。java
倒排索引是搜索引擎中常见的索引方法,用来存储在全文搜索下某个单词在一个文档中存储位置的映射。经过倒排索引,咱们输入一个关键词,能够很是快地获取包含这个关键词的文档列表。node
咱们先看英文的,假设咱们有两个文档:git
为了创建倒排索引,咱们先按最简单的用空格把每一个单词分开,能够获得以下结果:
*表示该列文档中有这个词条,为空表示没有该词条github
Term | doc1 | doc2 |
---|---|---|
I | * | * |
have | * | |
a | * | |
friend | * | |
who | * | |
loves | * | |
smile | * | |
love | * | |
me | * | |
you | * |
若是咱们要搜索 I love you,咱们只须要查找包含每一个词条的文档:架构
Term | doc1 | doc2 |
---|---|---|
I | * | * |
love | * | |
you | * |
两个文档都能匹配上,若是按命中词条数量来算,doc2比doc1更匹配。并发
这个是倒排索引最简化的表达方式,在ES的倒排索引存储结果中,还会记录每一个词条在文档中出现的位置。elasticsearch
咱们再看一下这个索引的创建过程,loves和love有区别吗?没有,都是爱的意思,一个是第三人称单数,一个是原形。若是能将一些语法的区别处理掉,这样的搜索结果是否是更切合实际需求?
例如:分布式
如今索引看上去成这样:高并发
Term | doc1 | doc2 |
---|---|---|
friend | * | |
love | * | * |
smile | * | |
me | * | |
you | * |
这样是否是精简了不少?
这个过程叫normalization,在创建倒排索引的时候,会执行一系列的操做,对拆分出的各个单词进行相应的处理,以提高后面搜索的时候可以搜索到相关联的文档的几率,如时态的转换,单复数的转换,同义词的转换,大小写的转换等。学习
分词器的做用就是把整篇文档,按必定的语义切分红一个一个的词条,目标是提高文档的召回率,并下降无效数据的噪音。
recall召回率,也叫可搜索性,指搜索的时候,增长可以搜索到的结果的数量。
降噪:指下降文档中一些低相关性词条对总体搜索排序结果的干扰。
文档的分词过程包含如下几步:
对字符串进行预处理,如HTML标签清洗<span>Love</span> --> Love,I & you --> I and you等等。
把字符串切分红单个的词条,如英文的按空格和标点切分,中文的按词语切分,针对不一样的语言,有不一样的分词器,有相对简单的标准分词器,也有特别复杂的中文分词器,里面包含了很是复杂的切分逻辑如:
I Love you --> I/Love/you
我和个人祖国 --> 我/和/个人/祖国
将分词器获得的词条进一步的处理,如改变词条(英文词干提取loves --> love),删除无实际意义的词条(英文的a, and, this,中文的"的","了","吗"),增长词条(补充同义词)
分词器很是重要,好的分词器能够显著提高召回率,不恰当的分词器获得的结果可能会对搜索产生歧义,最后处理好的结果再拿去创建倒排索引。
Elasticsearch自身提供了内置的分词器,也容许使用第三方的分词器。
ES默认分词器,根据Unicode联盟定义的单词边界划分文本,删除绝大部分标点,最后将词条小写。
在任何不是字母的地方分隔文本,将词条小写
在空格的地方划分文本
特定的语言的分词器,如english,英语分词器,维护了一组英语停用词and、the之类的,用于删除词条,针对英文语法规则,有提取单词词干的能力。
内置的分词器主要是对英文的支持效果比较好,中文则须要使用外部的分词器。
会将文本作最细粒度的拆分;尽量多的拆分出词语。
如南京市长江大桥 --> 南京市/南京/市长/长江大桥/长江/大桥
会作最粗粒度的拆分;已被分出的词语将不会再次被其它词语占有
如南京市长江大桥 --> 南京市/长江大桥
支持亚洲语言中文,日文,韩文
如南京市长江大桥 --> 南京/京市/市长/长江/江大/大桥
阿里自研的中文分词器
如南京市长江大桥 --> 南京/市/长江/大桥
外部分词器众多,开源也有不少,有针对不一样语言,不一样领域的,各位能够结合自身业务的特色,挑选适合本身的分词器,这里就不一一介绍了,有兴趣本身能够去了解一下。
以Elasticsearch 6.3.1版本为例,集成IK分词器,其余的分词器过程也相似,在ES的bin目录下执行插件安装命令便可:./elasticsearch-plugin install https://github.com/medcl/elasticsearch-analysis-ik/releases/download/v6.3.1/elasticsearch-analysis-ik-6.3.1.zip
其中install后面的那个的地址是 elasticsearch-analysis-ik 的github release对应ES版本的下载地址。
安装成功后,ES启动日志就能看到以下信息:[2019-11-27T12:17:15,255][INFO ][o.e.p.PluginsService] [node-1] loaded plugin [analysis-ik]
ES有analyze API来查看文本是如何被分词的,可用来作学习和调试用,请求命令以下:
GET /_analyze { "analyzer": "ik_max_word", "text": "南京市长江大桥" }
响应结果:
{ "tokens": [ { "token": "南京市", "start_offset": 0, "end_offset": 3, "type": "CN_WORD", "position": 0 }, { "token": "南京", "start_offset": 0, "end_offset": 2, "type": "CN_WORD", "position": 1 }, { "token": "市长", "start_offset": 2, "end_offset": 4, "type": "CN_WORD", "position": 2 }, { "token": "长江大桥", "start_offset": 3, "end_offset": 7, "type": "CN_WORD", "position": 3 }, { "token": "长江", "start_offset": 3, "end_offset": 5, "type": "CN_WORD", "position": 4 }, { "token": "大桥", "start_offset": 5, "end_offset": 7, "type": "CN_WORD", "position": 5 } ] }
本篇主要介绍了倒排索引的基本思路,展现了简化后的结构,并阐述了分词处理的基本步骤。目前市面上流行的分词器组件特别多,开源的社区也很是活跃,各位可根据实际的项目需求背景,挑选适合的进行集成 ,注意版本号的兼容性问题便可。
专一Java高并发、分布式架构,更多技术干货分享与心得,请关注公众号:Java架构社区