ElasticSearch 手记

其实在几年前就接触 Eleasticsearch 了,当时作为一个SA,并没有好好了解它的用法。最近在做搜索的功能,才发觉曾经对力量一无所知。

Mapping 创建 Schema

ES 使用前需要定义 mapping,相当于 MySQL 的 TableSchema,在创建 mapping 的时候,配置 type 的dynamic=strict,禁止未定义字段自动被添加到索引。

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
curl -XPUT "$URL/mall_goods_v1/?pretty" -H 'Content-Type:application/json' -d'
{
"mappings" : {
"goods": {
"dynamic": "strict",
"properties": {
"item_name": {
"type": "text",
"analyzer": "ik_max_word",
"search_analyzer": "ik_smart"
},
"item_code": {
"type": "keyword"
},
"status": {
"type": "integer"
},
"start_time":{
"type" : "date"
},
"group_ids": {
"type": "text",
"analyzer": "whitespace"
},
}
}
}
}';

中文分词

ES提供了IK分词器应对中文分词,它有两种分词模式:

  • ik_max_word:会将文本做最细粒度的拆分
  • ik_smart:会做最粗粒度的拆分
    两种分词器使用的最佳实践是:索引时用ik_max_word,在搜索时用 ik_smart。
    索引时最大化的将文章内容分词,搜索时更精确的搜索到想要的结果。

别名

给 ES 的 Index 起一个别名(alias) 能优雅解决两个索引无缝切换的问题,此功能在某些场景下非常使用。
举个例子:
如果发现 student_v1 的 Index 有问题,需重建一个 student_v2 的 Index, 我们可以给 student_v1 赋予一个别名 student,外界使用别名访问这个索引, 建好 student_v2 之后,将这个 student 别名指向 student_v2, 这样就可在外部无感知的情况下完成切换。

1
2
curl -XPOST "$URL/_aliases?pretty" -H 'Content-Type:application/json'  -d' 
{ "actions" : [ { "add" : { "index" : "student_v2", "alias" : "student" } } ] } '

ES 查询技巧

  • 只要不是 text 类型的字段,尽量使用 filter 过滤,因为它支持结果缓存,性能最佳。全文检索必须使用 must 而不是 filter,否则将导致 filter 缓存失效。

  • 自然语言检索应该用 “match” 查询,”term” 是不分词当成整体的。

  • 通过 termvector 查看一个字段的切分状况,用来辅助我们的查询语句是否正确

1
2
3
4
5
6
7
8
curl -XGET -H 'Content-Type:application/json' "http://$URL/mall_goods/goods/12954895599938508532/_termvectors?pretty" -d ' {
"fields" : [ "item_name"],
"offsets" : true,
"payloads" : true,
"positions" : true,
"term_statistics" : true,
"field_statistics" : true
} '