初次接触 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 你可以快速验证自己要定制的分词器,当达到自己需求后,再将这一部分配置加入索引的配置。

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

转载于:https://www.cnblogs.com/LoveShare/p/11239652.html

Elasticsearch 读时分词、写时分词相关推荐

  1. 进程共享(读时共享写时复制)

    父子进程之间在刚fork后.父子相同处: 全局变量..data..bbs..text.栈.堆.环境变量.用户ID.宿主目录(进程用户家目录).进程工作目录.信号处理方式等等,即0~3G的用户空间是完全 ...

  2. 写时拷贝/写时复制技术

    拷贝控制 C++提供两个拷贝控制函数 拷贝构造函数 拷贝赋值运算符重载 例如:String类 class String{public:String(const char* str = NULL);St ...

  3. JAVA使用es不分词_谈谈 Elasticsearch 分词和自定义分词

    初次接触 Elasticsearch 的同学经常会遇到分词相关的难题,比如如下这些场景: 1.为什么命名有包含搜索关键词的文档,但结果里面就没有相关文档呢? 2.我存进去的文档到底被分成哪些词(ter ...

  4. Redis的读更新和写更新-如何保证Redis与数据库的数据一致性

    背景 日前面试的时候被问到我们项目里面使用Redis的时候是如何更新缓存的,我的回答是写操作的时候的时候把缓存删了,然后读操作的时候就会读取出来最新的值.面试管继续问:Redis的写时更新和读时更新有 ...

  5. Apache Hudi的写时复制和读时合并

    Apache Hudi http://hudi.apache.org/ http://hudi.apache.org/docs/quick-start-guide.html Hudi是什么 Hudi将 ...

  6. 进程P1、P2、P3共享一个表格F,P1对F只读不写,P2对F只写不读,P3对F先读后写。进程可同时读F,但有进程写时,其他进程不能读和写。

    进程P1.P2.P3共享一个表格F,P1对F只读不写,P2对F只写不读,P3对F先读后写.进程可同时读F,但有进程写时,其他进程不能读和写.要求:(1)正常运行时不能产生死锁.(2)F的并发度要高. ...

  7. 数据库“写时模式”与“读时模式”对比

    schema on write与schema on read schema on write(写时模式) 作用于数据源到数据汇聚存储之间,典型使用就是传统数据库.数据不管是在入库还是采用装载外部数据或 ...

  8. String封装——读时共享,写时复制

    碰到过一位一直怀疑C++标准库(STL)效率的人,他说STL效率太低,企业开发根本不会用.我是持反对意见的. 说这话的人,肯定没有做过大量的调查.没有调查就没有发言权. STL的效率是不低的,足够满足 ...

  9. 搜索引擎——反向索引原理揭秘及手写ik分词器

    原创不易,转载请标明地址,或者直接附上我的博客首页https://georgedage.blog.csdn.net/ 上篇博客我们说到,数据库为什么不适合搜索引擎的底层存储?,那么什么适合呢? ela ...

  10. Elasticsearch笔记(五):分词器与文档管理

    在上一篇中已经对索引的相关知识做了一定的讲解,本章讲重点讲解分词器与文档操作的API的相关使用.当然了,分享还是基于es 6.2.x版本展开. 目录 1.倒序索引 2.分词器 2.1 分析器的结构组成 ...

最新文章

  1. python中string的操作函数
  2. mysql被格式化恢复数据_三种常见数据库文件恢复方法介绍
  3. python判断远程文件是否存在
  4. 使用sqoop将HIVE中的数据输出带Mysql中
  5. poco c++ 开发指南_掌握这个框架,你将会开发通杀全平台的万能爬虫
  6. Red5 webapp配置
  7. juc是什么java_JUC简介
  8. 华为交换机基本查询、目录、文件操作命令
  9. JVM虚拟机-Class文件之常量池
  10. element ui el-dialog 居中,并且内容多的时候内部可以滚动
  11. mysql 复制 错误_Mysql复制错误error
  12. three.js场景中看不到模型/看不到阴影
  13. oracle 创建一个用户,只能访问指定的对象
  14. 0点睡觉很会养生”苏宁高管的这话让IT人很憋屈
  15. 全网最全的人类图解析(上)——九大能量中心与64道闸门
  16. 一键安装ROS和rosdep(NO 墙)
  17. python中compile函数
  18. 关于在数据库中如何存储时间这件事
  19. RAW,RGB,YUV简单理解
  20. 如何将Asp.net 2.0网站部署到服务器

热门文章

  1. LeetCode--026--删除排序数组中的重复项(java)
  2. 书籍推荐:《Java数据结构与算法》
  3. Java 8中用java.time.LocalDate全面代替老旧的Date,Calendar类
  4. NGINX优化之路(一)
  5. Dev Express 安装
  6. Mapreduce和Yarn概念,参数优化,作用,原理,MapReduce计数器 Counter,MapReduce 多job串联之ControlledJob(来自学习资料)...
  7. 我的挨踢人物传之又是一年找工作时
  8. 谈如何边做事,边提高
  9. [Serializable]C#中的对象序列化
  10. 优秀的基于VUE移动端UI框架合集