ES分词配置

ES 中的分词是通过分词器来实现的,主要作用是将文本转化成单词,其主要分词器有 standard(默认分词器,单词转小写,去除标点符号),simple(单词转小写,去除标点符号和数字类型的字符),whitespace(去除空格,不支持中文)

standard 分词器

  1. standard 分词的过程

image.png

  1. 执行命令后可以看到,单词小写,标点符号也已经被去掉
1
2
3
4
5
GET _analyze
{
"analyzer": "standard",
"text": "Are you 18 years old, young man."
}
  1. 接着,将 text 的值修改为“中华人民共和国国歌”,执行后可以看到,中文按单个字进行分隔,并不符合我们要求,所以我们需要一个中文的分词器

ik 分词器

  1. 下载 ik 分词器:https://github.com/medcl/elasticsearch-analysis-ik/releases
  2. 将压缩包解压至 es 的 plugins 目录下后重启 es
  3. 执行命令后可以看到中文分词的结果
1
2
3
4
5
GET _analyze
{
"analyzer": "ik_max_word",
"text": "中华人民共和国国歌"
}

ik 分词器主要有两种,ik_smart(智能分词,粗粒度),ik_max_word(最大化分词,细粒度),使用时的最佳实践是创建索引时使用 max_word,查询的时候使用 smart,如果出现 smart 搜索不到的情况下,可以做降级强制指定 max_word 进行搜索

自定义词库

1
2
3
4
5
GET _analyze
{
"analyzer": "ik_max_word",
"text": "凯悦酒店"
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
{
"tokens" : [
{
"token" : "凯",
"start_offset" : 0,
"end_offset" : 1,
"type" : "CN_WORD",
"position" : 0
},
{
"token" : "悦",
"start_offset" : 1,
"end_offset" : 2,
"type" : "CN_WORD",
"position" : 1
},
{
"token" : "酒店",
"start_offset" : 2,
"end_offset" : 4,
"type" : "CN_WORD",
"position" : 2
}
]
}

因为“凯悦”这个词在词库中并不存在,所以执行上述命令时返回的结果并不是我们想要的,这时候就需要自定义词库进行处理

  1. 在 ik/config 目录下创建 new_word.dic 文件,输入文本“凯悦”
  2. 修改 IKAnalyzer.cfg.xml
1
2
<!--用户可以在这里配置自己的扩展字典 -->
<entry key="ext_dict">new_word.dic</entry>
  1. 重启 es 后执行 ik 分词,可以得到分词结果
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
{
"tokens" : [
{
"token" : "凯悦",
"start_offset" : 0,
"end_offset" : 2,
"type" : "CN_WORD",
"position" : 0
},
{
"token" : "酒店",
"start_offset" : 2,
"end_offset" : 4,
"type" : "CN_WORD",
"position" : 1
}
]
}

热更新词库

自定义词库创建后,需要重启 es 才会生效,一般不建议这么做,使用热更新的方式会更好
将文件配置改成可以用 http 请求访问即可,http 请求需要返回两个头部,last-modified 和 etag,两者任何一个发生变化则会重新更新,ik 一分钟检测一次

1
2
<!--用户可以在这里配置自己的扩展字典 -->
<entry key="ext_dict">http://yoursite.com/getCustomeDic</entry>

同义词搜索

  1. 在 es/config 目录创建 ik/synonyms.txt 文件,输入文本“凯悦,锡伯,红桃”
  2. 创建索引并添加数据
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
PUT /testindex2
{
"settings": {
"number_of_shards": 1,
"number_of_replicas": 1,
"analysis": {
"filter": {
"my_synonym_filter": {
"type": "synonym",
"synonyms_path": "ik/synonyms.txt"
}
},
"analyzer": {
"ik_syno": {
"type": "custom",
"tokenizer": "ik_smart",
"filter": ["my_synonym_filter"]
},
"ik_syno_max": {
"type": "custom",
"tokenizer": "ik_max_word",
"filter": ["my_synonym_filter"]
}
}
}
},
"mappings": {
"properties": {
"name": {
"type": "text",
"analyzer": "ik_syno_max",
"search_analyzer": "ik_syno"
}
}
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
PUT /testindex2/_doc/1
{
"name": "凯悦酒店"
}
PUT /testindex2/_doc/2
{
"name": "锡伯酒店"
}
PUT /testindex2/_doc/3
{
"name": "红桃酒店"
}
PUT /testindex2/_doc/4
{
"name": "测试酒店"
}
  1. 测试同义词搜索
1
2
3
4
5
GET /testindex2/_analyze
{
"field": "name",
"text": "凯悦"
}
1
2
3
4
5
6
7
8
GET /testindex2/_search
{
"query": {
"match": {
"name": "红挑"
}
}
}

返回数据:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
{
"tokens" : [
{
"token" : "凯悦",
"start_offset" : 0,
"end_offset" : 2,
"type" : "CN_WORD",
"position" : 0
},
{
"token" : "锡伯",
"start_offset" : 0,
"end_offset" : 2,
"type" : "SYNONYM",
"position" : 0
},
{
"token" : "红桃",
"start_offset" : 0,
"end_offset" : 2,
"type" : "SYNONYM",
"position" : 0
}
]
}