场景:
查询时出现“同一个DSL语句执行多次结果不一致”,如查询时返回的结果时而出现total=16,时而出现18...
配置:
refresh_interval = -1; 3节点;2 primary 1 replica;
分析:
主要的原因是因为有副本(replica)的存在,主分片和副本分片可能不一致,导致最终在主分片和副本分片上计算得到的得分不同,而导致最终的查询结果不一致。
不同的查询请求落到不同的分片上,获取到的文档集就可能不一致,最终才会出现hits.total一会是18,一会为16这种情况。
但是是如何造成主分片和副本分片不一致的情况?
1.可能是因为用户删除了部分文档,之后主分片进行了merge, 而副本分片没有进行merge。 这种情况下主分片和副本分片上的总文档数量就会不同,打分时计算出的IDF的值不同,最终得到了不同的得分。
2.当文档被删除或更新时,旧文档不会立即从索引中删除,它只是标记为已删除,并且仅在下次合并该旧文档所属的segment时才从磁盘中删除; 假设主分片刚刚完成了一个大型merge,删除了许多已删除的文档,那么它的索引统计信息可能与副本(仍具有大量已删除文档)完全不同(副本分片不会和主分片一起进行merge操作),因此得分也有所不同。
3.如果两个文档相关性评分相同,会根据其内部Lucene文档ID对其进行排序,两个文档相同的主分分片,luceneID不一定相同,导致最后的结果不一定相同
官方文档类似问题解释:https://www.elastic.co/guide/en/elasticsearch/reference/6.4/consistent-scoring.html
解决方案:
preference参数可以用来指定分片查询的优先级,可以通过该参数来控制搜索时的索引数据分片。
不设置该参数:在所有有效的主分片以及副本间轮询
可以用来处理结果震荡问题: 搜索同一query,结果ES返回的顺序却不尽相同,这就是请求轮询到不同分片,而未设置排序条件,相同相关性评分情况下,是按照所在segment中lucene id来排序的,相同数据的不同备份之间该id是不能保证一致的,故造成结果震荡问题。
如设置该参数,则有一下9种情况:
`_primary`:发送到集群的相关操作请求只会在主分片上执行。
`_primary_first`:指查询会先在主分片中查询,如果主分片找不到(挂了),就会在副本中查询。
`_replica`:发送到集群的相关操作请求只会在副本上执行。
`_replica_first`:指查询会先在副本中查询,如果副本找不到(挂了),就会在主分片中查询。
`_local`: 指查询操作会优先在本地节点有的分片中查询,没有的话再在其它节点查询。
`_prefer_nodes:abc,xyz`:在提供的节点上优先执行(在这种情况下为'abc'或'xyz')
`_shards:2,3`:限制操作到指定的分片。 (`2`和“3”)。这个偏好可以与其他偏好组合,但必须首先出现:`_shards:2,3 | _primary`
`_only_nodes:node1,node2`: 指在指定id的节点里面进行查询,如果该节点只有要查询索引的部分分片,就只在这部分分片中查找,不同节点之间用“,”分隔。
custom(自定义):注意自定义的preference参数不能以下划线"_"开头。 当preference为自定义时,即该参数不为空,且开头不以“下划线”开头时。
特别注意:如果以用户query作为自定义preference时,一定要处理以下划线开头的情况,这种情况下如果不属于以上8种情况,则会抛出异常。