ES自定义分析器

简述

在我们前面的文章介绍常用的中文相关分词器的时候,在测试时经常会用到自定义分析器来测试各种分析器的效果。而实际上我们在使用时通常情况下不会直接使用一个单一的分析器,例如ikpinyin等等。因为单一的分析器通常无法满足我们一些特殊要求。例如只使用ik分析器我们没办法做到近义词搜索,拼音搜索等功能。

前置知识点

在了解如何自定义分析器之前,我强烈推荐你先了解以下知识点:

  • 分析器的构成

  • ik分词器

  • pinyin分词器

  • 近义词搜索

如果不了解上面的知识点,你看该文章可能会有太多疑惑。不过没关系,关注公众号回复相关关键字即可推送相关内容文章。

分析器构成

之前有相关文章介绍分析器,这里只是大概地说一下分析器的构成。分析器由三个组件构成,分别为字符过滤器(char_filter)分词器(tokenizer)分词过滤器(filter)组成。其中字符过滤器和分词过滤器可有可无且可以多个,而分词器必须有且只能有一个。

ES自定义分析器
分析器构成

分析过程

分析器在对文本进行处理的整个过程分为三步:

  • 首先将文本内容给到字符过滤器处理,如果没有直接交给后续的分词器处理。如果有就对文本进行处理,它可以对内容进行添加、删除或者替换等操作来改变文本的原始内容。如果存在多个的话,则按顺序处理。
  • 经过字符过滤器处理之后,内容将交给分词器处理。分词器根据规则将内容拆分成一个个的词,然后交给后续处理。
  • 分词过滤器接收到词后,它可以对词进行转换大小写、添加近义词、删除停用词等操作,但是不会改变词原本的offset和position等属性。

自定义分析器

根据前面分析器相关知识现在我们知道了分析器是由什么组成的以及分析过程,而自定义分析器其实就是我们根据分析器的规则,自行的去组装一个分析器出来,然后分析器按照我们预想的执行顺序对文本进行处理。

例如现在我们检索的内容是一个网页,所以文档中还会存在html元素标签。并且这还是个二次元网页,这里面的还有很多颜文字,例如ORZ:-)之类的内容。同时我们支持使用近义词和拼音搜索。

字符过滤器

因为文档内容中有html标签,我们可以在索引前通过ES内部提供的HTML Strip Char Filter将html去掉,同时对于像颜文字之类的内容,我们可以使用Mapping Char Filter将其替换掉。

分词器

对于中文内容的分词,我们可以选择使用ik分词器。相对来说,ik分词器的分词效果还不错,同时还支持自定义扩展词典。

分词器只能配置一个

字符过滤器

对于近义词和拼音搜索,我们可以先使用ES内置的Synonym Token Filter增加近义词和使用pinyin分词器增加拼音。

构建自定义分析器

PUT /test_index
{
"settings": {
"analysis": {

"char_filter": {
"my_mapping_filter":{
"type":"mapping",
"mappings":["ORZ => 膜拜",":-) => 微笑"]
}
},

"filter": {
"my_synonym_filter":{
"type":"synonym_graph",
"expand":true,
"synonyms":["西红柿,番茄","土豆,洋芋,马铃薯"]
},
"my_pinyin_filter":{
"type":"pinyin",
"keep_original":"true"
}
},

"analyzer": {
"my_analyzer":{
"char_filter":["html_strip","my_mapping_filter"],
"tokenizer":"ik_smart",
"filter":["my_synonym_filter","my_pinyin_filter"]
}
}
}
},

"mappings": {
"properties": {
"content":{
"type":"text",
"analyzer": "my_analyzer"
}
}
}
}

根据前面的分析我们自定义的分析器代码如上所示:

  • char_filter此处为字符过滤器。my_mapping_filter是我们自定义字符过滤器的名字,其类型是Mapping Char Filter,并且设置了部分颜文字替换。

  • filter此处自定义两个分词器过滤器。my_synonym_filter是用来处理近义词的,my_pinyin_filter是用来处理拼音的。

  • analyzer此处为分析器。my_analyzer分析器就是自定义分析器的名字,它的字符过滤器由html_stripmy_mapping_filter组成,其中html_strap是ES内置的,而my_mapping_filter是我们自定义的。而分析器的分词器这里使用的是ik_smart分词器。字符过滤器这里使用的是自定义的my_synonym_filtermy_pinyin_filter

  • 最后定义了索引的结构,它只有一个字段content且其类型是text,注意其他类型ES是不会对其进行分析处理的。analyzer的值为my_analyzer这代表该字段索引都是使用的my_analyzer分析器。如果需要设置搜索时分析器,请配置search_analyzerm否则默认使用和索引时一样的分析器。

构建文档测试

先向ES插入部分测试数据

POST /test_index/_doc
{
"content":"<b>他对我ORZ,然后:-)跟我说他喜欢吃番茄不喜欢吃土豆</b>"
}

POST /test_index/_doc
{
"content":"<p>我做的西红柿鸡蛋汤很好喝,她膜拜我</p>"
}

POST /test_index/_doc
{
"content":"<h1>云南的炸洋芋</h1>"
}

颜文字搜索

GET /test_index/_search
{
"query": {
"match": {
"content": "微笑"
}
}
}

结果如下:

{
  "took" : 0,
  "timed_out" : false,
  "_shards" : {
    "total" : 1,
    "successful" : 1,
    "skipped" : 0,
    "failed" : 0
  },
  "hits" : {
    "total" : {
      "value" : 1,
      "relation" : "eq"
    },
    "max_score" : 2.7360926,
    "hits" : [
      {
        "_index" : "test_index",
        "_type" : "_doc",
        "_id" : "2lYTZYQBB-6GOouk2dwi",
        "_score" : 2.7360926,
        "_source" : {
          "content" : "<b>他对我ORZ,然后:-)跟我说他喜欢吃番茄不喜欢吃土豆</b>"
        }
      }
    ]
  }
}

近义词搜索

GET /test_index/_search
{
"query": {
"match": {
"content": "西红柿"
}
}
}

结果如下:

{
  "took" : 1,
  "timed_out" : false,
  "_shards" : {
    "total" : 1,
    "successful" : 1,
    "skipped" : 0,
    "failed" : 0
  },
  "hits" : {
    "total" : {
      "value" : 2,
      "relation" : "eq"
    },
    "max_score" : 3.5464158,
    "hits" : [
      {
        "_index" : "test_index",
        "_type" : "_doc",
        "_id" : "5lYVZYQBB-6GOoukCtwO",
        "_score" : 3.5464158,
        "_source" : {
          "content" : "<p>我做的西红柿鸡蛋汤很好喝,她膜拜我</p>"
        }
      },
      {
        "_index" : "test_index",
        "_type" : "_doc",
        "_id" : "2lYTZYQBB-6GOouk2dwi",
        "_score" : 3.4056468,
        "_source" : {
          "content" : "<b>他对我ORZ,然后:-)跟我说他喜欢吃番茄不喜欢吃土豆</b>"
        }
      }
    ]
  }
}

拼音搜索

GET /test_index/_search
{
"query": {
"match": {
"content": "xhs"
}
}
}

GET /test_index/_search
{
"query": {
"match": {
"content": "xihongshi"
}
}
}

运行结果如下:

{
  "took" : 1,
  "timed_out" : false,
  "_shards" : {
    "total" : 1,
    "successful" : 1,
    "skipped" : 0,
    "failed" : 0
  },
  "hits" : {
    "total" : {
      "value" : 2,
      "relation" : "eq"
    },
    "max_score" : 1.8563964,
    "hits" : [
      {
        "_index" : "test_index",
        "_type" : "_doc",
        "_id" : "5lYVZYQBB-6GOoukCtwO",
        "_score" : 1.8563964,
        "_source" : {
          "content" : "<p>我做的西红柿鸡蛋汤很好喝,她膜拜我</p>"
        }
      },
      {
        "_index" : "test_index",
        "_type" : "_doc",
        "_id" : "2lYTZYQBB-6GOouk2dwi",
        "_score" : 1.8387868,
        "_source" : {
          "content" : "<b>他对我ORZ,然后:-)跟我说他喜欢吃番茄不喜欢吃土豆</b>"
        }
      }
    ]
  }
}

总结

相信看完这篇文章你应该知道如何自定义分析器了,我这里只是粗略的去实现了一个搜索功能,实际上在工作中还需要各种优化。总的来说做搜索对于分析器来说没有固定的配置,实际上需要根据业务、检索的内容、准确率等一系列指标来测试才能找出符合自己业务需求的分析器。

原文始发于微信公众号(一只菜鸟程序员):ES自定义分析器

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/72845.html

(0)
小半的头像小半

相关推荐

发表回复

登录后才能评论
极客之音——专业性很强的中文编程技术网站,欢迎收藏到浏览器,订阅我们!