别再说你不会 ElasticSearch 调优了,都给你整理好了( 三 )


第三部分:通用的一些建议
1、不要 返回大的结果集
es 设计来作为搜索引擎,它非常擅长返回匹配 query 的 top n 文档 。但,如“返回满足某个query的 所有文档”等数据库领域的工作,并不是 es 最擅长的领域 。如果你确实需要返回所有文档,你可以使用 Scroll API
2、避免 大的 doc 。即,单个 doc 小了 会更好
given that(考虑到) http.max_context_length默认==100MB,es拒绝索引操作100MB的文档 。当然你可以提高这个限制,但,Lucene本身也有限制的,其为2GB
即使不考虑上面的限制,大的doc 会给 network/memory/disk带来更大的压力;
a.任何搜索请求,都需要获取 _id 字段,由于filesystem cache工作方式 。即使它不请求 _source字段,获取大doc _id 字段消耗更大
b.索引大doc时消耗内存会是 doc本身大小 的好几倍
c.大doc的 proximity search, highlighting 也更加昂贵 。它们的消耗直接取决于doc本身的大小
3、避免 稀疏
a.不相关数据 不要 放入同一个索引
b.一般化文档结构(Normalize document structures)
c.避免类型
d.在 稀疏 字段上,禁用 norms & doc_values 属性
稀疏为什么不好?
Lucene 背后的数据结构 更擅长处理 紧凑的数据
text类型的字段,norms默认开启;numerics, date, ip, keyword,doc_values默认开启
Lucene内部使用 integer的doc_id来标识文档 和 内部API交互 。
举个例子:
使用match查询时生成doc_id的迭代器,这些doc_id被用于获取它们的norm,以便计算score 。当前的实现是每个doc中保留一个byte用于存储norm值 。获取norm值其实就是读取doc_id位置处的一个字节
这非常高效,Lucene通过此值可以快速访问任何一个doc的norm值;但,给定一个doc,即使某个field没有值,仍需要为此doc的此field保留一个字节
doc_values也有同样的问题 。2.0之前的fielddata被现在的doc_values所替代了 。
稀疏性 最明显的影响是 对存储的需求(任何doc的每个field,都需要一个byte);但是呢,稀疏性 对 索引速度和查询速度 也是有影响的,因为:即使doc并没有某些字段值,但,索引时,依然需要写这些字段,查询时,需要skip这些字段的值
某个索引中拥有少量稀疏字段,这完全没有问题 。但,这不应该成为常态
稀疏性影响最大的是 norms&doc_values,但,倒排索引(用于索引 text以及keyword字段),二维点(用于索引geo_point字段)也会受到较小的影响
如何避免稀疏呢?
1、不相关数据 不要 放入同一个索引
给个tip:索引小(即:doc的个数较少),则,primary shard也要少
2、一般化文档结构(Normalize document structures)
3、避免类型(Avoid mapping type)
同一个index,最好就一个mapping type
在同一个index下面,使用不同的mapping type来存储数据,听起来不错,但,其实不好 。given that(考虑到)每一个mapping type会把数据存入 同一个index,因此,多个不同mapping type,各个的field又互不相同,这同样带来了稀疏性 问题
4、在 稀疏 字段上,禁用 norms & doc_values 属性
a.norms用于计算score,无需score,则可以禁用它(所有filtering字段,都可以禁用norms)
b.doc_vlaues用于sort&aggregations,无需这两个,则可以禁用它
但是,不要轻率的做出决定,因为 norms&doc_values无法修改 。只能reindex
秘诀1:混合 精确查询和提取词干(mixing exact search with stemming)
对于搜索应用,提取词干(stemming)都是必须的 。例如:查询 skiing时,ski和skis都是期望的结果
但,如果用户就是要查询skiing呢?
解决方法是:使用multi-field 。同一份内容,以两种不同的方式来索引存储
query.simple_query_string.quote_field_suffix,竟然是 查询完全匹配的
秘诀2:获取一致性的打分
score不能重现
同一个请求,连续运行2次,但,两次返回的文档顺序不一致 。这是相当坏的用户体验
如果存在 replica,则就可能发生这种事,这是因为:
search时,replication group中的shard是按round-robin方式来选择的,因此两次运行同样的请求,请求如果打到 replication group中的不同shard,则两次得分就可能不一致
那问题来了,“你不是整天说 primary和replica是in-sync的,是完全一致的”嘛,为啥打到“in-sync的,完全一致的shard”却算出不同的得分?
原因就是标注为“已删除”的文档 。如你所知,doc更新或删除时,旧doc并不删除,而是标注为“已删除”,只有等到 旧doc所在的segment被merge时,“已删除”的doc才会从磁盘删除掉


推荐阅读