简介:命名有包含搜索关键词的文档,但结果却没有?存进去的文档被分成哪些词(term)了?自定义分词规则,但感觉好麻烦呢,无从下手?

作者介绍

魏彬,普翔科技 CTO,开源软件爱好者,中国第一位 Elastic 认证工程师,《Elastic日报》和 《ElasticTalk》社区项目发起人,被 elastic 中国公司授予 2019 年度合作伙伴架构师特别贡献奖。对 Elasticsearch、Kibana、Beats、Logstash、Grafana 等开源软件有丰富的实践经验,为零售、金融、保险、证券、科技等众多行业的客户提供过咨询和培训服务,帮助客户在实际业务中找准开源软件的定位,实现从 0 到 1 的落地、从 1 到 N 的拓展,产生实际的业务价值。

初次接触 Elasticsearch 的同学经常会遇到分词相关的难题,比如如下这些场景:

1、为什么命名有包含搜索关键词的文档,但结果里面就没有相关文档呢?
2、我存进去的文档到底被分成哪些词(term)了?
3、我得自定义分词规则,但感觉好麻烦呢,无从下手

如果你遇到过类似的问题,希望本文可以解决你的疑惑。

一、上手

让我们从一个实例出发,如下创建一个文档:

PUT test/doc/1
{"msg":"Eating an apple a day keeps doctor away"
}

然后我们做一个查询,我们试图通过搜索 eat这个关键词来搜索这个文档

POST test/_search
{"query":{"match":{"msg":"eat"}}
}

ES的返回结果为0。这不太对啊,我们用最基本的字符串查找也应该能匹配到上面新建的文档才对啊!

各位不要急,我们先来看看什么是分词。

二、 分词

搜索引擎的核心是倒排索引(这里不展开讲),而倒排索引的基础就是分词。所谓分词可以简单理解为将一个完整的句子切割为一个个单词的过程。在 es 中单词对应英文为 term。我们简单看个例子:

ES 的倒排索引即是根据分词后的单词创建,即 我、爱、北京、天安门这4个单词。这也意味着你在搜索的时候也只能搜索这4个单词才能命中该文档。

实际上 ES 的分词不仅仅发生在文档创建的时候,也发生在搜索的时候,如下图所示:

读时分词发生在用户查询时,ES 会即时地对用户输入的关键词进行分词,分词结果只存在内存中,当查询结束时,分词结果也会随即消失。而写时分词发生在文档写入时,ES 会对文档进行分词后,将结果存入倒排索引,该部分最终会以文件的形式存储于磁盘上,不会因查询结束或者 ES 重启而丢失。

ES 中处理分词的部分被称作分词器,英文是Analyzer,它决定了分词的规则。ES 自带了很多默认的分词器,比如Standard、 Keyword、Whitespace等等,默认是 Standard。当我们在读时或者写时分词时可以指定要使用的分词器。

三、写时分词结果

回到上手阶段,我们来看下写入的文档最终分词结果是什么。通过如下 api 可以查看:

POST test/_analyze
{"field": "msg","text": "Eating an apple a day keeps doctor away"
}

其中 test为索引名,_analyze 为查看分词结果的 endpoint,请求体中 field 为要查看的字段名,text为具体值。该 api 的作用就是请告诉我在 test 索引使用 msg 字段存储一段文本时,es 会如何分词。

返回结果如下:

{"tokens": [{"token": "eating","start_offset": 0,"end_offset": 6,"type": "<ALPHANUM>","position": 0},{"token": "an","start_offset": 7,"end_offset": 9,"type": "<ALPHANUM>","position": 1},{"token": "apple","start_offset": 10,"end_offset": 15,"type": "<ALPHANUM>","position": 2},{"token": "a","start_offset": 16,"end_offset": 17,"type": "<ALPHANUM>","position": 3},{"token": "day","start_offset": 18,"end_offset": 21,"type": "<ALPHANUM>","position": 4},{"token": "keeps","start_offset": 22,"end_offset": 27,"type": "<ALPHANUM>","position": 5},{"token": "doctor","start_offset": 28,"end_offset": 34,"type": "<ALPHANUM>","position": 6},{"token": "away","start_offset": 35,"end_offset": 39,"type": "<ALPHANUM>","position": 7}]
}

返回结果中的每一个 token即为分词后的每一个单词,我们可以看到这里是没有 eat 这个单词的,这也解释了在上手中我们搜索 eat 没有结果的情况。如果你去搜索 eating ,会有结果返回。

写时分词器需要在 mapping 中指定,而且一经指定就不能再修改,若要修改必须新建索引。如下所示我们新建一个名为ms_english 的字段,指定其分词器为 english:

PUT test/_mapping/doc
{"properties": {"msg_english":{"type":"text","analyzer": "english"}}
}

四、读时分词结果

由于读时分词器默认与写时分词器默认保持一致,拿 上手 中的例子,你搜索 msg 字段,那么读时分词器为 Standard ,搜索 msg_english 时分词器则为 english。这种默认设定也是非常容易理解的,读写采用一致的分词器,才能尽最大可能保证分词的结果是可以匹配的。

然后 ES 允许读时分词器单独设置,如下所示:

POST test/_search{"query":{"match":{"msg":{"query": "eating","analyzer": "english"}}}}

如上 analyzer 字段即可以自定义读时分词器,一般来讲不需要特别指定读时分词器。

如果不单独设置分词器,那么读时分词器的验证方法与写时一致;如果是自定义分词器,那么可以使用如下的 api 来自行验证结果。

POST _analyze{"text":"eating","analyzer":"english"}

返回结果如下:

{"tokens": [{"token": "eat","start_offset": 0,"end_offset": 6,"type": "<ALPHANUM>","position": 0}]
}

由上可知 english分词器会将 eating处理为 eat,大家可以再测试下默认的 standard分词器,它没有做任何处理。

五、解释问题

现在我们再来看下 上手 中所遇问题的解决思路。

1、查看文档写时分词结果
2、查看查询关键词的读时分词结果
3、匹对两者是否有命中

我们简单分析如下:

由上图可以定位问题的原因了。

六、解决需求

由于 eating只是 eat的一个变形,我们依然希望输入 eat时可以匹配包含 eating的文档,那么该如何解决呢?

答案很简单,既然原因是在分词结果不匹配,那么我们就换一个分词器呗~ 我们可以先试下 ES 自带的 english分词器,如下:

# 增加字段 msg_english,与 msg 做对比
PUT test/_mapping/doc
{"properties": {"msg_english":{"type":"text","analyzer": "english"}}
}
# 写入相同文档
PUT test/doc/1
{"msg":"Eating an apple a day keeps doctor away","msg_english":"Eating an apple a day keeps doctor away"
}
# 搜索 msg_english 字段
POST test/_search
{"query": {"match": {"msg_english": "eat"}}
}

执行上面的内容,我们会发现结果有内容了,原因也很简单,如下图所示:

由上图可见 english分词器会将 eating分词为 eat,此时我们搜索 eat或者 eating肯定都可以匹配对应的文档了。至此,需求解决。

七、深入分析

最后我们来看下为什么english分词器可以解决我们遇到的问题。一个分词器由三部分组成:char filter、tokenizer 和 token filter。各部分的作用我们这里就不展开了,我们来看下 standard和english分词器的区别。

从上图可以看出,english分词器在 Token Filter 中和 Standard不同,而发挥主要作用的就是 stemmer,感兴趣的同学可以自行去看起它的作用。

八、自定义分词

如果我们不使用 english分词器,自定义一个分词器来实现上述需求也是完全可行的,这里不详细讲解了,只给大家讲一个快速验证自定义分词器效果的方法,如下:

POST _analyze
{"char_filter": [], "tokenizer": "standard","filter": ["stop","lowercase","stemmer"],"text": "Eating an apple a day keeps doctor away"
}

通过上面的 api 你可以快速验证自己要定制的分词器,当达到自己需求后,再将这一部分配置加入索引的配置。

至此,我们再看开篇的三个问题,相信你已经心里有答案了,赶紧上手去自行测试下吧!

声明:本文由原文《掌握 analyze API,一举搞定 Elasticsearch 分词难题》作者“魏彬”授权转载,对未经许可擅自使用者,保留追究其法律责任的权利。


【阿里云Elastic Stack】100%兼容开源ES,独有9大能力,提供免费X-pack服务(单节点价值$6000)

相关活动


更多折扣活动,请访问阿里云 Elasticsearch 官网

阿里云 Elasticsearch 商业通用版,1核2G ,SSD 20G首月免费
阿里云 Logstash 2核4G首月免费


原文链接:https://developer.aliyun.com/article/768351?

版权声明:本文中所有内容均属于阿里云开发者社区所有,任何媒体、网站或个人未经阿里云开发者社区协议授权不得转载、链接、转贴或以其他方式复制发布/发表。申请授权请邮件developerteam@list.alibaba-inc.com,已获得阿里云开发者社区协议授权的媒体、网站,在转载使用时必须注明"稿件来源:阿里云开发者社区,原文作者姓名",违者本社区将依法追究责任。 如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件至:developer2020@service.aliyun.com 进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容。

初次使用 Elasticsearch 遇多种分词难题?那是你没掌握这些原理相关推荐

  1. 掌握 analyze API,一举搞定 Elasticsearch 分词难题

    2019独角兽企业重金招聘Python工程师标准>>> 初次接触 Elasticsearch 的同学经常会遇到分词相关的难题,比如如下这些场景: 为什么明明有包含搜索关键词的文档,但 ...

  2. 【Elasticsearch】 Elasticsearch对外提供分词服务实践

    1.概述 转载:总结 | Elasticsearch对外提供分词服务实践 2. 问题抛出? 实战开发应用场景中,有获取一段话.一篇文章词频的业务场景, 词频的前提就是分词. 常用的中文分词包括: IK ...

  3. 【Elasticsearch】Elasticsearch analyzer 中文 分词器

    1.概述 转载: https://blog.csdn.net/tzs_1041218129/article/details/77887767 分词器首先看文章:[Elasticsearch]Elast ...

  4. ElasticSearch:为中文分词器增加对英文的支持(让中文分词器可以处理中英文混合文档)(转)

    本文地址,需转载请注明出处: http://blog.csdn.net/hereiskxm/article/details/47441911 当我们使用中文分词器的时候,其实也希望它能够支持对于英文的 ...

  5. Elasticsearch之Analyzer分词器介绍

    Elasticsearch之Analyzer分词器介绍 Analysis Analyzer的组成 ES中内置的分词器 Analyzer的使用 几种分词器介绍 Standard Analyzer Sim ...

  6. ElasticSearch最全分词器比较及使用方法

    介绍:ElasticSearch 是一个基于 Lucene 的搜索服务器.它提供了一个分布式多用户能力的全文搜索引擎,基于 RESTful web 接口.Elasticsearch 是用 Java 开 ...

  7. 2021年大数据ELK(八):Elasticsearch安装IK分词器插件

    全网最详细的大数据ELK文章系列,强烈建议收藏加关注! 新文章都已经列出历史文章目录,帮助大家回顾前面的知识重点. 目录 系列历史文章 安装IK分词器 一.下载Elasticsearch IK分词器 ...

  8. 为Elasticsearch添加中文分词

    Elasticsearch的中文分词很烂,所以我们需要安装ik.首先从github上下载项目,解压: cd /tmp wget https://github.com/medcl/elasticsear ...

  9. Elasticsearch之中文分词器插件es-ik(博主推荐)

    前提 什么是倒排索引? Elasticsearch之分词器的作用 Elasticsearch之分词器的工作流程 Elasticsearch之停用词 Elasticsearch之中文分词器 Elasti ...

最新文章

  1. [Nhibernate]SchemaExport工具的使用(二)——创建表及其约束、存储过程、视图
  2. 【若依(ruoyi)】shiro 内置的过滤器(filter)
  3. USACO-Section1.4 Ski Course Design (枚举)
  4. Servlet3.0
  5. JS 异步系列 —— Promise 札记
  6. Educational Codeforces Round 26 - A, B, C 思维
  7. 基于Java+Spring+vue+element实现旅游信息管理平台系统
  8. Ubuntu打印到pdf文件
  9. plc通过无线通讯连接服务器,PLC无线通讯
  10. 用C++计算圆周长和面积
  11. BLC(Black Level Correction)——黑电平校正
  12. 小鸡啄米之React事件处理
  13. 不花钱,模拟登录古诗中文网
  14. 音乐、房产可一键投资:资产证券化才是区块链的最大想象力?
  15. MySQL的文本导入load data local
  16. python自动点赞微信_基于AirTest+Python的ios自动化测试demo(微信朋友圈无限点赞)
  17. ORACLE经验汇总
  18. 计算机隐藏文件夹无法显示,隐藏文件夹无法显示怎么办【图文教程】
  19. Android列表ListView控件的使用
  20. python爬虫——Ajax-get

热门文章

  1. mysql开启慢查询
  2. Matplotlib绘制动态曲线图,超简单!!
  3. 大小仅1MB,超轻量级通用人脸检测模型登上GitHub趋势榜
  4. java 8 string_java8、jdk8日期转化成字符串
  5. bootstrap mysql分页_bootstrap分页
  6. 判断图有无环_判断无向图/有向图中是否存在环
  7. python中的pandas怎么安装_如何优雅的安装Python的pandas?
  8. DeepLearning.AI第一部分第三周、 浅层神经网络(Shallow neural networks)
  9. Eclipse远程调试HDP源代码
  10. iOS开发之SQLite--C语言接口规范(三)——Binding Values To Prepared Statements