ES基于分布式,每一個搜索請求都是分發(fā)到所有的分片上單獨處理,最后匯總結果。聚合也是這樣操作。但是在這種邏輯下,會導致某些聚合的結果不準確,即實現group邏輯的terms桶
例子
curl -X GET "localhost:9200/cars/transactions/_search" -H 'Content-Type: application/json' -d'
{
"size" : 0,
"aggs" : {
"popular_colors" : {
"terms" : {
"field" : "color",
"size": 3
}
}
}
}
這里實現了一個terms聚合,以color為依據進行分組統計。結果為每種color的個數。下面是返回的結果
{
...
"hits": {
"hits": []
},
"aggregations": {
"doc_count_error_upper_bound": 3,
"sum_other_doc_count": 10,
"popular_colors":
"buckets": [
{
"key": "red",
"doc_count": 4
},
{
"key": "blue",
"doc_count": 2
},
{
"key": "green",
"doc_count": 2
}
]
}
}
}
在返回結果的aggregations中,有三個值:doc_count_error_upper_bound、sum_other_doc_count和popular_colors。這三個值表示了ES對這次聚合的評估和返回的聚合結果。
- doc_count_error_upper_bound:表示沒有在這次聚合中返回、但是可能存在的潛在聚合結果,這里的值為 3,表除去red、blue和green之外,還可能有一個聚合結果為 3。從返回結果看,可能會排在第二名。
- sum_other_doc_count:表示這次聚合中沒有統計到的文檔數。因為ES為分布式部署,不同文檔分散于多個分片,這樣當聚合時,會在每個分片上分別聚合,然后由協調節(jié)點匯總結果后返回。這里因為請求的是排名前三的聚合,所以每個分片只聚合了本分片中排名前三的color。其他沒有統計到的文檔數由每個節(jié)點返回后,匯總為此元素。這里值為 10,表示有10個文檔沒有參與此次聚合。
- popular_colors:聚合結果,默認由高到低排列。key表示聚合元素的值,doc_count表示元素出現的次數。注意,這里的doc_count也是不準確的。
由此分析這一次的聚合,雖然返回了top3,但是可能存在另一個第二名,而且doc_count只是一個相對值。
本質上這種誤差是由于分布式環(huán)境中的數據隔離產生的,尤其是當獲取topK數據時,節(jié)點內的topK準確不保證整體topK準確。而且無論元素還是元素對應的doc_count,都不是準確的。
所以如果想要ES獲取準確的聚合結果,只有max、min、avg等聚合可以做到,而terms API本身不保證準確,只有通過一些額外的方法來確保或者提高準確性:
- 不分片,所有數據在一個shard上。這樣可以使ES在聚合中使用所有數據,為完全準確。
- 在聚合中使用route,將需要聚合的數據路由到同一個節(jié)點上。將這樣需要數據結構和業(yè)務邏輯的支持,一般數據很難實現。
- 提高聚合結果的數量。這樣可以使每一個分片節(jié)點返回更多的冗余數據,在協調節(jié)點進行數據匯總時,提高聚合結果的準確性。這種方法只保證聚合結果的近似準確,推薦使用。