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


索引统计(index statistic)是打分时非常重要的一部分,但,由于 deleted doc 的存在,在同一个shard的不同copy(即:各个replica)上 计算出的 索引统计 并不一致
个人理解:
a. 所谓 索引统计 应该就是df,即 doc_freq
b. 索引统计 是基于shard来计算的

  1. 搜索时,“已删除”的doc 当然是 永远不会 出现在 结果集中的
  2. 索引统计时,for practical reasons,“已删除”doc 依然是统计在内的
假设,shard A0 刚刚完成了一次较大的segment merge,然后移除了很多“已删除”doc,shard A1 尚未执行 segment merge,因此 A1 依然存在那些“已删除”doc
于是:两次请求打到 A0 和 A1 时,两者的 索引统计 是显著不同的
如何规避 score不能重现 的问题?使用 preference 查询参数
发出搜索请求时候,用 标识字符串 来标识用户,将 标识字符串 作为查询请求的preference参数 。这确保多次执行同一个请求时候,给定用户的请求总是达到同一个shard,因此得分会更为一致(当然,即使同一个shard,两次请求 跨了 segment merge,则依然会得分不一致)
这个方式还有另外一个优点,当两个doc得分一致时,则默认按着doc的 内部Lucene doc id 来排序(注意:这并不是es中的 _id 或 _uid) 。但是呢,shard的不同copy间,同一个doc的 内部Lucene doc id 可能并不相同 。因此,如果总是达到同一个shard,则,具有相同得分的两个doc,其顺序是一致的
score 错了(Relevancy looks wrong)
如果你发现具有相同内容的文档,其得分不同,完全匹配 的查询 并没有排在第一位,这可能都是由 sharding 引起的,默认情况下,搜索文档时,每个shard自己计算出自己的得分 。索引统计 又是打分时一个非常重要的因素 。
如果每个shard的 索引统计相似,则 搜索工作的很好
文档是平分到每个primary shard的,因此 索引统计 会非常相似,打分也会按着预期工作 。但,万事都有个但是:索引时使用了 routing(文档不能平分到每个primary shard 啦),查询多个索引,索引中文档的个数 非常少,这会导致:参与查询的各个shard,各自的 索引统计 并不相似(而,索引统计对 最终的得分 又影响巨大),于是 打分出错了(relevancy looks wrong)
那,如何绕过 score错了(Relevancy looks wrong)?
如果数据集较小,则,只使用一个primary shard(es默认是5个),这样两次查询 索引统计 不会变化,因而得分也就一致啦
另一种方式是,将search_type设置为:dfs_query_then_fetech(默认是query_then_fetch)
dfs_query_then_fetch的作用是向 所有相关shard 发出请求,要求 所有相关shard 返回针对当前查询的 索引统计,然后,coordinating node 将 merge这些 索引统计,从而得到 merged statistics coordinating node 要求 所有相关shard 执行 query phase,于是 发出请求,这时,也带上 merged statistics 。这样,执行query的shard 将使用 全局的索引统计 。大部分情况下,要求 所有相关shard 返回针对当前查询的 索引统计,这是非常cheap的 。但,如果查询中 包含 非常大量的 字段/term查询,或者有 fuzzy查询,此时,获取 索引统计 可能并不cheap,因为 为了得到 索引统计 可能 term dictionary 中 所有的term都需要被查询一遍
英文文章地址:https://www.elastic.co/guide/en/elasticsearch/reference/current/how-to.html

【别再说你不会 ElasticSearch 调优了,都给你整理好了】


推荐阅读