es 精确查询不模糊_ES系列17:Terms聚合结果不精确,怎么破?
?點擊上方“方才編程”,即可關注我!
寫在前面關于更新:
其實持續不斷的輸出,還是需要點東西的,不僅是知識點的學習和沉淀,更多是內驅力。學習一個知識點,梳理腦圖,到demo的編寫,格式的調整,是一個費時費力的活。但很奇怪,在停更的這兩個月,總感覺缺少點什么,國慶將至,人也閑了下來,決定接著肝下去,能肝多久?不知道!希望自己能一路走下去,From Zero To Hero!今天突然發現微信官方給了一個“讀者討論”功能,還是很開心的。【我們最好的關系就是互相成就,大家的點贊、在看、分享就是我創作的最大動力!】留言也是一種鼓勵喲,期待大家的討論。關于本文:
之前詳解介紹了ES的各種聚合操作,關于Terms聚合的精度問題,本來也打算自己寫的,后來發現銘毅大佬已經解釋得很清楚了,所以就簡單提煉了下,轉載了。【ps:國慶節打算把“ES的Analyzer原理、高亮原理”肝出來,也不知道還沒有小伙伴看】terms聚合
本文概覽?
1、實戰開發遇到聚合問題
請教一個問題,ES 在聚合的時候發生了一個奇怪的現象聚合的語句里面size設置為10和大于10導致聚合的數量不一致,這個size不就是返回的條數嗎?會影響統計結果嗎?dsl語句摘要(手機敲不方便,雙引號就不寫了):
aggs:{topcount:{terms:{field:xx,size:10}}}就是這個size,設置10和大于10將會導致聚合結果不一樣,難道是es5.x的bug嗎?
以上是實戰中的真實問題,基于這個問題,有了本篇文章。
本文探討的聚合主要指:terms 分桶聚合。下圖為分桶 terms 聚合示意圖。
從一堆多分類的產品中聚合出 TOP 3 的產品分類和數量。TOP3 結果:
產品 Y:4產品 X:3
產品 Z:2
2、前提認知:Elasticsearch terms 分桶聚合結果是不精確的
2.1 Elasticsearch 分片 和 副本
Elasticsearch 索引由一個或多個主分片以及零個或者多個副本分片組成。
索引的大小超過了單個節點的硬件限制,分片就可以解決。
分片包含索引數據的一個子集,并且本身具有完全的功能和獨立性,你可以將分片視為“獨立索引”。
分片的核心要義:
- 分片可以拆分并擴展數據量。如果數據量不斷增加,將會遇到存儲瓶頸。舉例:有1TB的數據,但只有兩個節點(單節點512GB存儲)?單獨無法存儲,切分分片后,問題游刃有余的解決。
- 操作可以分布在多個節點上,從而可以并行化提高性能。
主分片:寫入過程先寫主分片,寫入成功后再寫入副本分片,恢復階段也以主分片為主。
副本分片的目的:
- 在節點或分片發生故障時提供高可用性。
副本分片永遠不會分配給與主分片相同的節點。
- 提高搜索查詢的性能。
因為可以在所有主、副本上并行執行搜索、聚合操作。
2.2 分片的分配機制
Elasticsearch 如何知道要在哪個分片上存儲新文檔,以及在通過 ID 檢索它時如何找到它?
默認情況下,文檔應在節點之間平均分配,這樣就不會有一個分片包含的文檔比另一個分片多非常多。
確定給定文檔應存儲在哪個分片的機制稱為:路由。
為了使 Elasticsearch 盡可能易于使用,默認情況下會自動處理路由,并且大多數用戶不需要手動 reroute 處理它。
Elasticsearch 使用如下圖的簡單的公式來確定適當的分片。
shard?=?hash(routing)?%?total_primary_shards- routing: 文檔 id,可以自己指定或者系統生成 UUID。
- total_primary_shards:主分片數。
這里推演一道面試題:一旦創建索引后,為什么無法更改索引的主分片數量?
考慮如上路由公式,我們就可以找到答案。
如果我們要更改分片的數量,那么對于文檔,運行路由公式的結果將發生變化。
假設:設置有 5 個分片時文檔已存儲在分片 A 上,因為那是當時路由公式的結果。
后面我們將主分片更改為7個,如果再嘗試通過ID查找文檔,則路由公式的結果可能會有所不同。
現在,即使文檔實際上存儲在Shard A上,該公式也可能會路由到ShardB。這意味著永遠不會找到該文檔。
以此可以得出:主分片創建后不能更改的結論。
較真的同學,看到這里可能會說:不是還有 Split 切分分片和 Shrink 壓縮分片機制嗎?
畢竟Split?和 Shrink? 對分片的處理是有條件的(如:都需要先將分片設置為只讀)。
所以,長遠角度還是建議:提前根據容量規模和增量規模規劃好主分片個數。
2.3 Elasticsearch 如何檢索 / 聚合數據?
接收客戶端請求的節點為:協調節點。如下圖中的節點 1 。
在協調節點,搜索任務被分解成兩個階段:query 和 fetch 。
真正搜索或者聚合任務的節點稱為:數據節點。如下圖中的:節點 2、3、4。
聚合步驟:
- 客戶端發送請求到協調節點。
- 協調節點將請求推送到各數據節點。
- 各數據節點指定分片參與數據匯集工作。
- 協調節點進行總結果匯集。
2.4 示例說明 聚合結果不精確
集群:3個節點,3個主分片,每個分片有5個產品的數據。用戶期望返回Top 3結果如下:
產品X:40產品A:40
產品Y:35
用戶執行如下 terms 聚合,期望返回集群 prodcuts 索引Top3 結果。
POST?products/_search{"size":0,"aggs":?{"product_aggs":?{"terms":?{"field":"name.keyword","size":3
??????}
????}
??}
}
實際執行如下圖所示:各節點的分片:取自己的Top3 返回給協調節點。協調節點匯集后結果為:
產品Y:35,?產品X:?35,
產品A:30。
這就產生了實際聚合結果和預期聚合結果不一致,也就是聚合結果不精確。
導致聚合不精確的原因分析:
- 效率因素:每個分片的取值Top X,并不是匯總全部的 TOP X。
- 性能因素:ES 可以不每個分片Top X,而是全量聚合,但勢必這會有很大的性能問題。
3、如何提高聚合精確度?
思考題——terms 聚合中的 size 和 shard_size 有什么區別?
- size:是聚合結果的返回值,客戶期望返回聚合排名前三,size值就是 3。
- shard_size: 每個分片上聚合的數據條數。shard_size 原則上要大于等于 size(若設置小于size,實則沒有意義,elasticsearch 會默認置為size)
請求的size值越高,結果將越準確,但計算最終結果的成本也將越高。
那到底如何提供聚合精準度呢?這里提供了四種方案供參考:
方案1:設置主分片為1
注意7.x版本已經默認為1。
適用場景:數據量小小集群規模業務場景。
方案2:調大 shard_size 值
設置 shard_size 為比較大的值,官方推薦:size*1.5+10
適用場景:數據量大、分片數多的集群業務場景。
shard_size 值越大,結果越趨近于精準聚合結果值。
此外,還可以通過show_term_doc_count_error參數顯示最差情況下的錯誤值,用于輔助確定 shard_size 大小。
方案3:將size設置為全量值,來解決精度問題
將size設置為2的32次方減去1也就是分片支持的最大值,來解決精度問題。
原因:1.x版本,size等于 0 代表全部,高版本取消 0 值,所以設置了最大值(大于業務的全量值)。
全量帶來的弊端就是:如果分片數據量極大,這樣做會耗費巨大的CPU 資源來排序,而且可能會阻塞網絡。
適用場景:對聚合精準度要求極高的業務場景,由于性能問題,不推薦使用。
方案4:使用Clickhouse 進行精準聚合
在星球微信群里,張超大佬指出:分析系統里跑全量的 group by 我覺得是合理的需求, clickhouse很擅長做這種事,es如果不在這方面加強,分析場景很多會被 clickhouse替掉。
騰訊大佬指出:聚合這塊比較看場景。因為我這邊有一些業務是做聚合,也就是 olap 場景,多維分析,ES并不是特別擅長。如果有豐富的多維分析場景,還有比較高的性能要求。我建議可以調研下clickhouse。我們這邊測評過開源和內部的 大部分場景 clickhouse 幾十億的級別,基本也在秒級返回甚至毫秒級。
此外,除了 chlickhouse, spark也有類似聚合的功能。
適用場景:數據量非常大、聚合精度要求高、響應速度快的業務場景。
4、小結
回到開頭提到的問題,設置10和大于10將會導致聚合結果不一樣是由于 Elasticsearch 聚合實現機制決定的,不是Bug。Elasticsearch本身不提供精準分桶聚合。要提高聚合精度,參考文章提到的幾種方案。
大家有更好的精度提升方案,歡迎留言交流。
待續
●ES系列13:徹底掌握相關度●ES系列14:Bucket Aggs●ES系列15:ES的指標聚合有哪些呢?你點的每個贊,我都認真當成了喜歡總結
以上是生活随笔為你收集整理的es 精确查询不模糊_ES系列17:Terms聚合结果不精确,怎么破?的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 如何找到PC端爱奇艺APP上的手机扫描登
- 下一篇: kdj超卖_kdj超买超卖是什么意思?k