专栏首页铭毅天下Elasticsearch自定义分词,从一个问题说开去

Elasticsearch自定义分词,从一个问题说开去

1、问题抛出

来自星友的一个真实业务场景问题: 我现在的业务需求是这样的。有一个作者字段,比如是这样的Li,LeiLei;Han,MeiMei;还有一些是LeiLei Li...。 现在要精确匹配。 我的想法是:用自定义分词通过分号分词。但是这样我检索Li,LeiLei那么LeiLei Li就不能搜索到,我希望的结果是LeiLei Li也被搜索到。 而且这种分词,Li,LeiLei不加逗号,也不能匹配到。但是不知道为什么我在mapping里面添加停用词也不管用?

2、本文思路

问题出发,由浅入深逐步探讨

  1. 为什么需要分词?
  2. 文档转换为倒排索引,发生了什么?
  3. Elasticsearch自带的分词器
  4. 自定义分词器的模板
  5. 针对问题,实践一把

3、为什么需要分词?

中文分词是自然语言处理的基础。

  1. 语义维度:单字很多时候表达不了语义,词往往能表达。分词相当于预处理,能使后面和语义有关的分析更准确。
  2. 存储维度:如果所有文章按照单字来索引,需要的存储空间和搜索计算时间就要多的多。
  3. 时间维度:通过倒排索引,我们能以o(1) 的时间复杂度,通过词组找到对应的文章。

同理的,英文或者其他语种也需要分词。

设计索引的Mapping阶段,要根据业务用途确定是否需要分词,如果不需要分词,建议设置keyword类型;需要分词,设置为text类型并指定分词器

推荐阅读:干货 | 论Elasticsearch数据建模的重要性

分词使用的时机: 1)创建或更新文档时,会对文档做分词处理。 2)查询时,会对查询语句进行分词处理。

4、文档转换为倒排索引,发生了什么?

注意:如下文档中部分关键词的翻译后反而不好理解,部分关键词我会使用和官方一致的英文关键词。 文档被发送并加入倒排索引之前,Elasticsearch在其主体上的操作称为分析(analysis)。

而analysis的实现可以是Elasticsearch内置分词器(analyzer)或者是自定义分词器。

Analyzer的由如下三部分组成:

4.1 character filters 字符过滤

字符过滤器将原始文本作为字符流接收,并可以通过添加,删除或更改字符来转换字符流。

字符过滤分类如下:

  1. HTML Strip Character Filter. 用途:删除HTML元素,如<b>,并解码HTML实体,如&amp
  2. Mapping Character Filter 用途:替换指定的字符。
  3. Pattern Replace Character Filter 用途:基于正则表达式替换指定的字符。

4.2 tokenizers 文本切分为分词

接收字符流(如果包含了4.1字符过滤,则接收过滤后的字符流;否则,接收原始字符流),将其分词。 同时记录分词后的顺序或位置(position),以及开始值(start_offset)和偏移值(end_offset-start_offset)。

tokenizers分类如下:

  1. Standard Tokenizer
  2. Letter Tokenizer
  3. Lowercase Tokenizer …..

详细需参考官方文档。

4.3 token filters分词后再过滤

针对tokenizers处理后的字符流进行再加工,比如:转小写、删除(删除停用词)、新增(添加同义词)等。

是不是看着很拗口,甚至不知所云。

没关系,但,脑海中的这张三部分组成的图以及三部分的执行顺序一定要加深印象。

5、Elasticsearch自带的Analyzer

5.1 Standard Analyzer

标准分析器是默认分词器,如果未指定,则使用该分词器。 它基于Unicode文本分割算法,适用于大多数语言。

5.2 Whitespace Analyzer

基于空格字符切词。

5.3 Stop Analyzer

在simple Analyzer的基础上,移除停用词。

5.4 Keyword Analyzer

不切词,将输入的整个串一起返回。 ……. 更多分词器参考官方文档。

6、自定义分词器的模板

自定义分词器的在Mapping的Setting部分设置。

PUT my_custom_index
{
"settings":{
"analysis":{
"char_filter":{},
"tokenizer":{},
"filter":{},
"analyzer":{}
}
}
}

脑海中还是上面的三部分组成的图示。 其中:

  1. "char_filter":{},——对应字符过滤部分;
  2. "tokenizer":{},——对应文本切分为分词部分;
  3. "filter":{},——对应分词后再过滤部分;
  4. "analyzer":{}——对应分词器组成部分,其中会包含:1. 2. 3。

7、针对问题,实践一把

7.1 问题拆解

核心问题1:实际检索中,名字不带","。 逗号需要字符过滤掉。在char_filter阶段实现。

核心问题2:思考基于什么进行分词? Li,LeiLei;Han,MeiMei;的构成中,只能采用基于“;"分词方式。

核心问题3:支持姓名颠倒后的查询。 即:LeileiLi也能被检索到。 需要结合同义词实现。

在分词后再过滤阶段,将:LiLeiLeiLeiLeiLi设定为同义词。

7.2 实践

基于问题的答案如下:

PUT my_index
{
  "settings": {
    "analysis": {
      "char_filter": {
        "my_char_filter": {
          "type": "mapping",
          "mappings": [
            ", => "
          ]
        }
      },
      "filter": {
        "my_synonym_filter": {
          "type": "synonym",
          "expand": true,
          "synonyms": [
            "lileilei => leileili",
            "hanmeimei => meimeihan"
          ]
        }
      },
      "analyzer": {
        "my_analyzer": {
          "tokenizer": "my_tokenizer",
          "char_filter": [
            "my_char_filter"
          ],
          "filter": [
            "my_synonym_filter"
          ]
        }
      },
      "tokenizer": {
        "my_tokenizer": {
          "type": "pattern",
          "pattern": "\\;"
        }
      }
    }
  },
  "mappings": {
    "_doc": {
      "properties": {
        "text": {
          "type": "text",
          "analyzer": "my_analyzer"
        }
      }
    }
  }
}

7.3 analyze API的妙处

用途

  1. 实际业务场景中,检验分词的正确性。
  2. 排查检索结果和预期不一致问题的利器。

用法1:直接验证分词结果。

GET my_index/_analyze 
{
  "analyzer": "my_analyzer", 
  "text":     "Li,LeiLei"
}

用法2:基于索引字段验证分词结果。

GET my_index/_analyze 
{
  "field": "my_text", 
   "text":     "Li,LeiLei"
}

8、小结

  • 自定义分词这块,我认为不大好理解。光是:1)"char_filter":2)"tokenizer" 3)"filter" 4)"analyzer"就很容易把人绕进去。
  • 网上中文文档的各种翻译不完全一致,很容易误导,官方英文文档的解读会更准确。
  • 要牢记图中三部分的组成,结合实际业务场景具体分析+实践会加深自定义分词的理解。

参考: 1、官方文档 2、rockybean教程

本文分享自微信公众号 - 铭毅天下(gh_0475cf887cf7),作者:铭毅天下

原文出处及转载信息见文内详细说明,如有侵权,请联系 yunjia_community@tencent.com 删除。

原始发表时间:2019-04-05

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • 漫画趣解:透析Elasticsearch原理

    小史是一个非科班的程序员,虽然学的是电子专业,但是通过自己的努力成功通过了面试,现在要开始迎接新生活了。

    铭毅天下
  • 探究 | 明明存在,怎么搜索不出来呢?

    wildcard模糊匹配不也可以全字段模糊查询,进而得到结果呢? 但是,当文档结果集非常大,模糊匹配必然会有性能问题。

    铭毅天下
  • 干货 | Elasticsearch Nested类型深入详解

    本文通过一个例子将Nested类型适合解决的问题、应用场景、使用方法串起来, 文中所有的DSL都在Elasticsearch6.X+验证通过。

    铭毅天下
  • 大数据项目之_15_帮助文档_NTP 配置时间服务器+Linux 集群服务群起脚本+CentOS6.8 升级到 python 到 2.7

      当集群中各个节点的时间不同步,误差超过某个范围时,会导致一些集群的服务无法正常进行,这时我们应该想办法做一个定时同步集群所有节点时间的任务。

    黑泽君
  • 12306网站:分布式内存数据技术为查询提速75倍

    问题导读: 1、什么是GemFire分布式内存数据技术? 2、12306购票网站是如何实现大规模访问? 摘要: 背景和需求   中国铁路客户服务中心网...

    用户1410343
  • 使用 Nginx 部署前后端分离项目,解决跨域问题

    前后端分离这个问题其实松哥和大家聊过很多了,上周松哥把自己的两个开源项目部署在服务器上以帮助大家可以快速在线预览(喜大普奔,两个开源的 Spring Boot ...

    江南一点雨
  • 什么是 Visual VM?

    VisualVM 提供在 Java 虚拟机 (Java Virutal Machine, JVM) 上运行的 Java 应用程序的详细信息。在 VisualVM...

    cloudskyme
  • Android旁门左道之动态替换应用程序

    导语 本文讲述如何通过替换应用程序类的方法,可以协助开发调试甚至应用于项目中。 作者: yarkeyzhang  2017.8.31 一,引子 继...

    MelonTeam
  • 聊聊dubbo-go的ProviderAuthFilter

    dubbo-go-v1.4.2/filter/filter_impl/auth/provider_auth.go

    codecraft
  • 创建华丽 UI 的 7条规则 第一部分 (2019年更新)

    这可能是关于 UI 设计最重要又容易被忽视一个内容:光来自天空。 光线来自天空,从上往上,以至于从下往上的光让人看起来很怪异。

    前端小智@大迁世界

扫码关注云+社区

领取腾讯云代金券