一、IK分词器

全民制作人,大家好,我是练习时长2年半的个人练习生亚瑟王,喜欢ES、钢琴、鼓励队友。

ES默认的standard分词器对中文不友好,会将中文分割成一个个汉字。对于中文分词,目前比较常用的是IK分词器。IK分词器的作者对这个项目维护的比较积极,能紧跟ES的最新版本。

安装IK分词器的教程网上太多了,我这里就不再赘述了。本篇博客仅仅记录我自己学习IK的一些小小心得。

1. 创建测试的Mapping和数据

  • nameanalyzer是默认的standard,对于姓名这样的中文,适合用standard,因为姓名中一般没有固定的词组。
  • wordanalyzerik_max_wordsearch_analyzerik_smart
PUT pigg_test_ik
{
    "mappings":{
        "properties":{
            "name":{
                "type":"text",
                "analyzer":"standard"
            },
            "word":{
                "type":"text",
                "analyzer":"ik_max_word",
                "search_analyzer":"ik_smart"
            }
        }
    }
}

插入测试数据

PUT pigg_test_ik/_doc/1
{
  "name": "亚瑟王",
  "word": [
      "亚瑟王爱弹琴"
  ]
}

2. 查看文档如何存储

执行如下命令,看字符串是如何拆分后索引的

GET pigg_test_ik/_doc/1/_termvectors?fields=name
GET pigg_test_ik/_doc/1/_termvectors?fields=word

字段

词条

name

亚、瑟、王

word

亚瑟、王、亚瑟王、爱、弹琴

3. 在name上match查询

  • 因为name是"analyzer":"standard",所以搜索的关键词会拆成一个个独立的字。
  • 只要关键词中包含亚、瑟、王中任意一个字,都算匹配成功。
GET pigg_test_ik/_search
{
  "query": {
    "match": {
      "name": "i瑟" //拆成"i"和"瑟","瑟"命中文档
    }
  }
}
  • 但是如果修改matchoperatorand,则需要所有字全部命中
GET pigg_test_ik/_search
{
  "query": {
    "match": {
      "name": {
        "query": "i瑟", //因为有"i",所以没有匹配到文档
        "operator": "and"
      }
    }
  }
}

4. 在word上match查询

word字段上为啥analyzerik_max_word,而search_analyzerik_smart呢?

  • ik_max_word会尽可能拆分出更多的词条组合
  • ik_smart则相对智能,不会拆的很细

我们先来看下这2个分析器对亚瑟王爱弹琴是如何处理的。

POST pigg_test_ik/_analyze
{
  "analyzer": "ik_smart",
  "text": "亚瑟王爱弹琴"
}

POST pigg_test_ik/_analyze
{
  "analyzer": "ik_max_word",
  "text": "亚瑟王爱弹琴"
}

analyzer

词条

ik_smart (搜索时)

亚瑟王、爱、弹琴

ik_max_word (索引时)

亚瑟、王、亚瑟王、爱、弹琴

通过上表,可以看出在好处是保存文档时,已经索引尽可能多的词,而在搜索文档时,没有必要对搜索关键字拆分的很细,这样提高了查询的效率。

"亚瑟王"会拆分成"亚瑟王"这1个词条,直接拿"亚瑟王"去匹配文档,可以匹配成功

GET pigg_test_ik/_search
{
  "query": {
    "match": {
      "word": "亚瑟王" //会拆分成"亚瑟王"这1个词条,直接拿"亚瑟王"去匹配文档,可以匹配成功
    }
  }
}

"瑟王"会拆分成"瑟""王"这2个词条,"瑟"这个字匹配不到文档,但是"王"这个字可以匹配到文档

GET pigg_test_ik/_search
{
  "query": {
    "match": {
      "word": "瑟王" //会拆分成"瑟"和"王"这2个词条,"瑟"这个字匹配不到文档,但是"王"这个字可以匹配到文档
    }
  }
}

使用如下命令解释为何"瑟王"能匹配到文档

GET pigg_test_ik/_explain/1
{
  "query": {
    "match": {
      "word": "瑟王"
    }
  }
}

返回结果中显示如下:

"description" : "weight(word:王 in 1) [PerFieldSimilarity], result of:",

说明是"王"这个字匹配到文档的。

5. 自定义字典

在ik的config目录下创建ext.dic文本文件,添加一些自定义的扩展词

es 安装jieba分词器 es 默认分词器_ik


修改如下的配置文件,指定扩展字典的文件名

es 安装jieba分词器 es 默认分词器_es 安装jieba分词器_02


上面操作执行好了后,一定要重启ES,否则是不生效的。