Elasticsearch 读时分词、写时分词
初次接触 Elasticsearch 的同学经常会遇到分词相关的难题,比如如下这些场景:
为什么明明有包含搜索关键词的文档,但结果里面就没有相关文档呢?我存进去的文档到底被分成哪些词(term)了?我自定义分词规则,但感觉好麻烦呢,无从下手
如果你遇到过类似的问题,希望本文可以解决你的疑惑。
1. 上手
让我们从一个实例出发,如下创建一个文档:
然后我们做一个查询,我们试图通过搜索 eat 这个关键词来搜索这个文档
ES的返回结果为0。这不太对啊,我们用最基本的字符串查找也应该能匹配到上面新建的文档才对啊!
各位不要急,我们先来看看什么是分词。
2. 分词
搜索引擎的核心是倒排索引(这里不展开讲),而倒排索引的基础就是分词。所谓分词可以简单理解为将一个完整的句子切割为一个个单词的过程。在 es 中单词对应英文为 term 。我们简单看个例子:
ES 的倒排索引即是根据分词后的单词创建,即我、爱、北京、天安门这4个单词。这也意味着你在搜索的时候也只能搜索这4个单词才能命中该文档。
实际上 ES 的分词不仅仅发生在文档创建的时候,也发生在搜索的时候,如下图所示:
读时分词发生在用户查询时,ES 会即时地对用户输入的关键词进行分词,分词结果只存在内存中,当查询结束时,分词结果也会随即消失。而写时分词发生在文档写入时,ES 会对文档进行分词后,将结果存入倒排索引,该部分最终会以文件的形式存储于磁盘上,不会因查询结束或者 ES 重启而丢失。
ES 中处理分词的部分被称作分词器,英文是Analyzer,它决定了分词的规则。ES 自带了很多默认的分词器,比如Standard、Keyword、Whitespace等等,默认是Standard。当我们在读时或者写时分词时可以指定要使用的分词器。
3. 写时分词结果
回到上手阶段,我们来看下写入的文档最终分词结果是什么。通过如下 api 可以查看:
其中test为索引名,_analyze为查看分词结果的endpoint,请求体中field为要查看的字段名,text为具体值。该 api 的作用就是请告诉我在 test 索引使用 msg 字段存储一段文本时,es 会如何分词。
返回结果如下:
返回结果中的每一个token即为分词后的每一个单词,我们可以看到这里是没有eat这个单词的,这也解释了在上手中我们搜索eat没有结果的情况。如果你去搜索eating,会有结果返回。
写时分词器需要在 mapping 中指定,而且一经指定就不能再修改,若要修改必须新建索引。如下所示我们新建一个名为ms_english的字段,指定其分词器为english:
4. 读时分词结果
由于读时分词器默认与写时分词器默认保持一致,拿 上手 中的例子,你搜索msg字段,那么读时分词器为Standard,搜索msg_english时分词器则为english。这种默认设定也是非常容易理解的,读写采用一致的分词器,才能尽最大可能保证分词的结果是可以匹配的。
然后 ES 允许读时分词器单独设置,如下所示:
如上analyzer字段即可以自定义读时分词器,一般来讲不需要特别指定读时分词器。
如果不单独设置分词器,那么读时分词器的验证方法与写时一致;如果是自定义分词器,那么可以使用如下的 api 来自行验证结果。
返回结果如下:
由上可知english分词器会将eating处理为eat,大家可以再测试下默认的standard分词器,它没有做任何处理。
5. 解释问题
现在我们再来看下 上手 中所遇问题的解决思路。
查看文档写时分词结果查看查询关键词的读时分词结果匹对两者是否有命中
我们简单分析如下:
由上图可以定位问题的原因了。
6. 解决需求
由于eating只是eat的一个变形,我们依然希望输入eat时可以匹配包含eating的文档,那么该如何解决呢?答案很简单,既然原因是在分词结果不匹配,那么我们就换一个分词器呗~ 我们可以先试下 ES 自带的english
分词器,如下:
执行上面的内容,我们会发现结果有内容了,原因也很简单,如下图所示:
由上图可见english分词器会将eating分词为eat,此时我们搜索eat或者eating肯定都可以匹配对应的文档了。至此,需求解决。
7. 深入分析
最后我们来看下为什么english分词器可以解决我们遇到的问题。一个分词器由三部分组成:char filter、tokenizer 和 token filter。各部分的作用我们这里就不展开了,我们来看下standard和english分词器的区别。
从上图可以看出,english分词器在 Token Filter 中和Standard不同,而发挥主要作用的就是stemmer,感兴趣的同学可以自行去看其它的作用。
8. 自定义分词
如果我们不使用english分词器,自定义一个分词器来实现上述需求也是完全可行的,这里不详细讲解了,只给大家讲一个快速验证自定义分词器效果的方法,如下:
通过上面的 api 你可以快速验证自己要定制的分词器,当达到自己需求后,再将这一部分配置加入索引的配置。
至此,我们再看开篇的三个问题,相信你已经心里有答案了,赶紧上手去自行测试下吧!
Elasticsearch 读时分词、写时分词的更多相关文章
- php变量 写时改变 写时复制
写时复制 $var = 1; $var2 = $var; #此时$var2 与 $var 指向同一个zval refcount = 2: $var = 2; # 此时$val 改变 所以 $var 与 ...
- [ES]elasticsearch章5 ES的分词(一)
初次接触 Elasticsearch 的同学经常会遇到分词相关的难题,比如如下这些场景: 1.为什么明明有包含搜索关键词的文档,但结果里面就没有相关文档呢? 2.我存进去的文档到底被分成哪些词(ter ...
- Redis持久化之父子进程与写时复制
之所以将Linux底层的写时复制技术放在Redis篇幅下,是因为Redis进行RDB持久化时,BGSAVE(后面称之为"后台保存")会开辟一个子进程,将数据从内存写进磁盘,这儿我产 ...
- 读时加写锁,写时加读锁,Eureka可真的会玩
大家好,我是三友~~ 在对于读写锁的认识当中,我们都认为读时加读锁,写时加写锁来保证读写和写写互斥,从而达到读写安全的目的.但是就在我翻Eureka源码的时候,发现Eureka在使用读写锁时竟然是在读 ...
- String封装——读时共享,写时复制
碰到过一位一直怀疑C++标准库(STL)效率的人,他说STL效率太低,企业开发根本不会用.我是持反对意见的. 说这话的人,肯定没有做过大量的调查.没有调查就没有发言权. STL的效率是不低的,足够满足 ...
- ElasticSearch已经配置好ik分词和mmseg分词(转)
ElasticSearch是一个基于Lucene构建的开源,分布式,RESTful搜索引擎.设计用于云计算中,能够达到实时搜索,稳定,可靠,快速,安装使用方便.支持通过HTTP使用JSON进行数据索引 ...
- ES 09 - 定制Elasticsearch的分词器 (自定义分词策略)
目录 1 索引的分析 1.1 分析器的组成 1.2 倒排索引的核心原理-normalization 2 ES的默认分词器 3 修改分词器 4 定制分词器 4.1 向索引中添加自定义的分词器 4.2 测 ...
- [ES]elasticsearch章5 ES的分词(二)
Elasticsearch 中文搜索时遇到几个问题: 当搜索关键词如:“人民币”时,如果分词将“人民币”分成“人”,“民”,“币”三个单字,那么搜索该关键词会匹配到很多包含该单字的无关内容,但是如果将 ...
- Linux下,非Docker启动Elasticsearch 6.3.0,安装ik分词器插件,以及使用Kibana测试Elasticsearch,
Linux下,非Docker启动Elasticsearch 6.3.0 查看java版本,需要1.8版本 java -version yum -y install java 创建用户,因为elasti ...
随机推荐
- Spark Scala当中reduce的用法和例子
[学习笔记] reduce将RDD中元素前两个传给输入函数,产生一个新的return值,将新产生的return值与RDD中下一个元素(即第三个元素)组成两个元素,再被传给输入函数,这样递归运作,直到最 ...
- 剑指offer20:定义栈的数据结构,请在该类型中实现一个能够得到栈中所含最小元素的min函数(时间复杂度应为O(1))。
1 题目描述 定义栈的数据结构,请在该类型中实现一个能够得到栈中所含最小元素的min函数(时间复杂度应为O(1)). 2. 思路和方法 利用辅助栈来存储现有栈的最小值.在入栈和出栈的时候将现有栈和最小 ...
- windows下memcache扩展安装和搭建
### windows下memcache扩展安装和搭建 背景:在做微信公众号的开发时,token的有效期为7200秒,所以需要对token进行保存,在这选择了memcache作为缓存工具 memcac ...
- __setitem__和__getitem__和__delitem__
__setitem__和__getitem__和__delitem__ class Foo: def __init__(self, name): self.name = name def __geti ...
- Spring实战(四)Spring高级装配中的bean profile
profile的原意为轮廓.剖面等,软件开发中可以译为“配置”. 在3.1版本中,Spring引入了bean profile的功能.要使用profile,首先要将所有不同的bean定义整理到一个或多个 ...
- Windows编程 Windows程序的生与死(上)
引子 “Windows 程序分为‘程序代码’和‘UI(User Interface)资源’两大部份,两部份最后以RC编译器(资源编译器)整合为一个完整的EXE 文件.所谓UI 资源是指功能菜单.对话框 ...
- .NET Core 创建Windows服务
.NET Core 创建Windows服务 作者:高堂 原文地址:https://www.cnblogs.com/gaotang/p/10850564.html 写在前面 使用 TopShelf+Au ...
- Pytorch报错:cuda runtime error (59) : device-side assert triggered at /pytorch/aten/src/THC/generic/THCTensorMath.cu:26
Pytorch报错:cuda runtime error (59) : device-side assert triggered at /pytorch/aten/src/THC/generic/TH ...
- Docker Registry搭建
一.前言 Docker官方镜像仓库 访问速度很慢,Docker Registry允许搭建我们自己的镜像仓库,为实现镜像拉取.推送提供便利. 二.安装与启动 1.创建目录 mkdir /usr/loca ...
- Spring事务的配置、参数详情及其原理介绍(Transactional)
Spring 事务管理分为编程式和声明式的两种方式.编程式事务指的是通过编码方式实现事务:声明式事务基于 AOP,将具体业务逻辑与事务处理解耦.声明式事务管理使业务代码逻辑不受污染, 因此在实际使用中 ...