初次接触 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": "",

"position": 0

},

{

"token": "an",

"start_offset": 7,

"end_offset": 9,

"type": "",

"position": 1

},

{

"token": "apple",

"start_offset": 10,

"end_offset": 15,

"type": "",

"position": 2

},

{

"token": "a",

"start_offset": 16,

"end_offset": 17,

"type": "",

"position": 3

},

{

"token": "day",

"start_offset": 18,

"end_offset": 21,

"type": "",

"position": 4

},

{

"token": "keeps",

"start_offset": 22,

"end_offset": 27,

"type": "",

"position": 5

},

{

"token": "doctor",

"start_offset": 28,

"end_offset": 34,

"type": "",

"position": 6

},

{

"token": "away",

"start_offset": 35,

"end_offset": 39,

"type": "",

"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": "",

"position": 0

}

]

}

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

五、解释问题

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

1、查看文档写时分词结果

2、查看查询关键词的读时分词结果

3、匹对两者是否有命中

我们简单分析如下:

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

六、解决需求

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

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

JAVA使用es不分词_谈谈 Elasticsearch 分词和自定义分词相关推荐

  1. php 搜索引擎 分词_PHP使用elasticsearch搜索安装及分词方法

    一.背景 为什么会用到这个ES搜索? 是因为我在看乌云的漏洞案例库时候,搜索即为不方便. 比如说说我要搜索一个 SQL注入 那mysql匹配的时候是like模糊匹配,搜索必须要有SQL注入这四个字,连 ...

  2. elasticsearch analysis模块 自定义分词 拼音分词 同义词 停词

    Analysis Analysis 解析器由三个模块=character filters(字符过滤器), tokenizers(标记器), and token filters(标记过滤器)组成 Ana ...

  3. mysql怎么把表中的内容分词_用mysql数据库写的分词算法代码

    我辛苦的整了几天才整好的 拿来给大家分享一下希望可以帮助大家 以下分为四步:每步都有注释说明的 #region 一.先从article表里查询数据 /// /// 一.先从article表里查询数据 ...

  4. java es 如何查询_使用elasticsearch的java-api进行查询

    1.前言 elsaticsearch版本是6.8.3,使用的java-api是基于Java High Level REST Client.java 2.数据 3.  InitClient 用来初始化客 ...

  5. java 对象引用 弱引用吗_谈谈Java对象的强引用,软引用,弱引用,虚引用分别是什么...

    整体结构 java提供了4中引用类型,在垃圾回收的时候,都有自己的各自特点. 为什么要区分这么多引用呢,其实这和Java的GC有密切关系. 强引用(默认支持模式) 把一个对象赋给一个引用变量,这个引用 ...

  6. java异常处理方式推荐做法_谈谈Java异常处理这件事儿

    此文已由作者谢蕾授权网易云社区发布. 欢迎访问网易云社区,了解更多网易技术产品运营经验. 前言 我们对于"异常处理"这个词并不陌生,众多框架和库在异常处理方面都提供了便利,但是对于 ...

  7. java url路径包含中文_谈谈 Java 类加载机制

    概述 类加载器主要分为两类,一类是 JDK 默认提供的,一类是用户自定义的. JDK 默认提供三种类加载器: Bootstrap ClassLoader 启动类加载器:每次执行 java 命令时都会使 ...

  8. 对java的集合的理解_谈谈你对java集合类的理解

    数组是集合的一种,是集合的一个子集,你理解了数组就理解了集合.理解集合类集合类存放于java.util包中.集合类存放的都是对象的引用,而非对象本身,出于表达上的便利,我们称集合中的对象就是指集合中对 ...

  9. java开发用amd处理器_谈谈AMD CPU购机心得 与 写代码的感受

    序 之前用的是华硕飞行保垒.具体是几代忘记了..I7 4代的标压CUP. 8G内存 换成了联想yoga 14s. 换电脑的原因 网卡问题,老旧的网卡争网络实在争不过别人.每次看别人网络很好,我却连不上 ...

最新文章

  1. 公众号第三方平台开发 获取 component_verify_ticket
  2. 行为翻译模型是人脑的核心
  3. (0071)iOS开发之Category VS Extension区别理解
  4. Socket编程(C语言实现)—— 为什么流式传输类似于管道?不区分边界?
  5. html方框中能放置图片么,html中的img标签你不知道的那些细节!
  6. laravel 初识
  7. 惠普m1005连接电脑步骤_电脑连接电视机详细步骤方法图文
  8. 党建活动献爱心,达飞云贷冬日送温暖
  9. python 串口助手 简书_pySerial 串口工具简介
  10. 计算机无法连接移动硬盘,移动硬盘无法访问怎么办 移动硬盘无法访问解决方法...
  11. Collected errors: * opkg_conf_load: Could not lock /var/lock/opkg.lock: Resource temporarily unavail
  12. 金色传说:SAP-FICO-参考加权因素维护执行成本中心分配 KSV5/KSV3报错GA603:系统错误:集01018000D06表CCSS读出错
  13. 用C 制作含万年历的台历(2009年样张)之1
  14. 图灵奖得主Jack Dongarra:高性能计算与AI大融合,如何颠覆科学计算
  15. 使用VirtualLab Fusion对闪耀光栅分析
  16. 用Python打造一款3D医疗影像识别系统
  17. 4.25学习笔记 哈希表
  18. Dynamic Few-Shot Visual Learning without Forgetting
  19. RoboMasterAI挑战赛-装甲板识别与测距 jetsonNX+realsense
  20. java中set和ge什么么意思,java的Collection和Map详解

热门文章

  1. cetus(cetus talk)
  2. C++之面向对象(下)
  3. 面经经历--滴滴,科大讯飞
  4. 苹果开发者账号认证(五步超简单)
  5. JavaScript判断浏览器内核,微信打开自动提示在浏览器打开
  6. Rails服务器推送技术
  7. 139邮箱短信报警实现
  8. 2019,成立个人独资企业还能节税吗?具体怎样操作?
  9. 大话C#之WPF实践场景入门进阶,深入浅出解析教程 25 逻辑判断必知必会入门解析
  10. 阿里云服务器配置个人开发者怎么选择?