1.優化聚合查詢示例
假設咱們如今有一些關於電影的數據集,每條數據裏面會有一個數組類型的字段存儲表演該電影的全部演員的名字。
{
"actors" : [
"Fred Jones",
"Mary Jane",
"Elizabeth Worthing"
]
}
若是咱們想要查詢出演影片最多的十個演員以及與他們合做最多的演員,使用聚合是很是簡單的:數組
{
"aggs" : {
"actors" : {
"terms" : {
"field" : "actors",
"size" : 10
},
"aggs" : {
"costars" : {
"terms" : {
"field" : "actors",
"size" : 5
}
}
}
}
}
}
這會返回前十位出演最多的演員,以及與他們合做最多的五位演員。這看起來是一個簡單的聚合查詢,最終只返回 50 條數據!
可是, 這個看上去簡單的查詢能夠垂手可得地消耗大量內存,咱們能夠經過在內存中構建一個樹來查看這個 terms 聚合。 actors 聚合會構建樹的第一層,每一個演員都有一個桶。而後,內套在第一層的每一個節點之下, costar 聚合會構建第二層,每一個聯合出演一個桶。這意味着每部影片會生成 n2 個桶!
2.深度優先和廣度優先原理
Elasticsearch 容許咱們改變聚合的 集合模式 ,就是爲了應對這種情況。
咱們以前展現的策略叫作 深度優先 ,它是默認設置, 先構建完整的樹,而後修剪無用節點。 深度優先 的方式對於大多數聚合都能正常工做,但對於如咱們演員和聯合演員這樣例子的情形就不太適用。
爲了應對這些特殊的應用場景,咱們應該使用另外一種集合策略叫作 廣度優先 。這種策略的工做方式有些不一樣,它先執行第一層聚合, 再 繼續下一層聚合以前會先作修剪。
在咱們的示例中, actors 聚合會首先執行,在這個時候,咱們的樹只有一層,但咱們已經知道了前 10 位的演員!這就沒有必要保留其餘的演員信息,由於它們不管如何都不會出如今前十位中。由於咱們已經知道了前十名演員,咱們能夠安全的修剪其餘節點。修剪後,下一層是基於 它的 執行模式讀入的,重複執行這個過程直到聚合完成。
要使用廣度優先,只需簡單 的經過參數 collect 開啓:
{
"aggs" : {
"actors" : {
"terms" : {
"field" : "actors",
"size" : 10,
"collect_mode" : "breadth_first"
},
"aggs" : {
"costars" : {
"terms" : {
"field" : "actors",
"size" : 5
}
}
}
}
}
}
廣度優先僅僅適用於每一個組的聚合數量遠遠小於當前總組數的狀況下,由於廣度優先會在內存中緩存裁剪後的僅僅須要緩存的每一個組的全部數據,以便於它的子聚合分組查詢能夠複用上級聚合的數據。
廣度優先的內存使用狀況與裁剪後的緩存分組數據量是成線性的。對於不少聚合來講,每一個桶內的文檔數量是至關大的。 想象一種按月分組的直方圖,總組數確定是固定的,由於每一年只有12個月,這個時候每月下的數據量可能很是大。這使廣度優先不是一個好的選擇,這也是爲何深度優先做爲默認策略的緣由。
針對上面演員的例子,若是數據量越大,那麼默認的使用深度優先的聚合模式生成的總分組數就會很是多,可是預估二級的聚合字段分組後的數據量相比總的分組數會小不少因此這種狀況下使用廣度優先的模式能大大節省內存,從而經過優化聚合模式來大大提升了在某些特定場景下聚合查詢的成功率。