ElasticSearch 使用技巧
其实在几年前就接触 Eleasticsearch 了,当时作为一个SA,并没有好好了解它的用法。最近在做搜索的功能,才发觉曾经对力量一无所知。
Mapping 创建 Schema
ES 使用前需要定义 mapping,相当于 MySQL 的 TableSchema,在创建 mapping 的时候,配置 type 的dynamic=strict,禁止未定义字段自动被添加到索引。
1 | curl -XPUT "$URL/mall_goods_v1/?pretty" -H 'Content-Type:application/json' -d' |
中文分词
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 | curl -XPOST "$URL/_aliases?pretty" -H 'Content-Type:application/json' -d' |
ES 查询技巧
只要不是 text 类型的字段,尽量使用 filter 过滤,因为它支持结果缓存,性能最佳。全文检索必须使用 must 而不是 filter,否则将导致 filter 缓存失效。
自然语言检索应该用 “match” 查询,”term” 是不分词当成整体的。
通过 termvector 查看一个字段的切分状况,用来辅助我们的查询语句是否正确
1 | curl -XGET -H 'Content-Type:application/json' "http://$URL/mall_goods/goods/12954895599938508532/_termvectors?pretty" -d ' { |
- 版本号更新
Elasticsearch 是分布式的。当文档创建、更新或删除时, 新版本的文档必须复制到集群中的其他节点。Elasticsearch 也是异步和并发的,这意味着这些复制请求被并行发送,并且到达目的地时也许顺序是乱的 。 Elasticsearch 需要一种方法确保文档的旧版本不会覆盖新的版本。 检查当前 _version 是否 小于 指定的版本号。 如果请求成功,外部的版本号作为文档的新 _version 进行存储.
常见的方法是通过增加 version_type = external , 然后使用时间戳做版本号更新来保证旧文档不会覆盖新文档。
1 | PUT /website/blog/2?version=5&version_type=external |
- 提供排序权重
ES默认是按照 BM25 来计算分数的。比如以下例子,
用户输入qwe 我们需要搜索出名字中包含这些字符的记录
1 | GET group_member_v1/_search |
实际上我们希望,qwe 连在一起的 nickname 权重可以更高,排序更前,于是引用进了 const_score
和 match_phrase
1 | GET group_member_v1/_search |
Suggester
completion suggest,常叫做自动完成(auto completion) 也叫搜索推荐。
比如说我们在搜索歌曲,搜索”月亮”,百度自动给你提示 “月亮代表我的心”, “月亮之上”, 搜索引擎会自动提示补全,借助 ES 的 Suggester 也有这个功能。看如下的例子
1 | PUT /songs_index |
查询语句
1 | GET /song_indexs/songs/_search |
删除指定记录
1 | POST school_rank_v1/rank/_delete_by_query |