一、背景
這周在使用Elasticsearch搜索的時候遇到一個,對於同一個搜索請求,會出現top50返回結果和排序不一致的問題。那么為什么會出現這樣的問題?
后來通過百度和google,發現這是因為Elastcisearch的分布式搜索特性導致。Elasticsearch在搜索時,會循環的選擇主分片和其副本中的一個來計算和返回搜索結果,而由於主分片和副本中相關統計信息的不同,從而導致了同一個搜索串的評分的不一致,進而導致排序不一樣。而造成這種主分片和副本統計信息不一致的具體原因,是因為文檔刪除時造成的,具體可以參考官方給出的解釋:https://www.elastic.co/guide/en/elasticsearch/reference/current/consistent-scoring.html
二、解決辦法
針對上述問題,Elasticsearch官方也給出了解決方案(https://www.elastic.co/guide/en/elasticsearch/guide/2.x/_search_options.html#_preference),即在搜索時設置preference特性。如下:
SearchRequestBuilder builder = client.prepareSearch(offLin.index)
.setTypes(offLin.type)
.setQuery(queryBuilder)
.setFetchSource(fetchFields, null)
.setSize(limit)
.setPreference("_primary_first");
那么preference可以取哪些值,每個值的含義是什么呢,可以參考下面解釋:
(1)randomizeacross shards:隨機選擇分片或其副本查詢數據,es的默認方式。
(2)_local:優先在本地節點上的分片查詢數據然后再去其他節點上的分片查詢,本地節點沒有IO問題但有可能造成負載不均問題。
(3)_primary:搜索只在主分片執行搜索請求,副本不參與搜索;性能會打折扣,達不到性能的水平擴展。
(4)_primary_first:優先在主分片執行,如果主分片掛掉,會在副本執行請求。
(5)_only_node:123 :只在123這個節點執行搜索。
(6)_prefer_node:123:搜索請求優先在節點123執行。
(7)_shards:1,2:搜索只在分片2、3執行,可以與_primary參數一起使用如:_shards:2,3;_primary
(8)隨機字符串:指定一個隨機字符串,可以保證同樣的請求,被分配到同樣的副本上面,從而保證同一請求結果的穩定性。我遇到的問題就可以使用這種方式,把搜索串的hash值作為隨機字符串,這樣可以保證同一個搜索條件的請求的返回結果和排序一致。