這里有一篇很好的文章,很不錯,翻譯和整理了一下,英文不錯的,建議直接看原文:http://euphonious-intuition.com/2013/05/all-about-elasticsearch-filter-bitsets/
elasticsearch里面有BOOL filter、AND、OR、NOT filter,這幾個看起來很相似,都有什么區別呢?什么時候用boolfilter?什么時候用AND filter呢?
事實上,bool filter和AND 、OR、NOT filter 是完全不同,在查詢性能上面的影響是非常大的。
首先咱們需要了解的是filter里面都是怎么工作的,其中核心的一個東西叫BitSet,可以理解為一個很大的bit數組,數組里面的每個元素有2個狀態:0和1(bloom filter知道么?),而filter大家都知道,只處理文檔是否匹配與否,不涉及文檔評分操作。如果一個文檔和filter查詢匹配,那么其對應的bit位就設置為1,匹配不上則設置為0。
es在執行filter查詢過濾的時候,會打開lucene的每個segment段文件,然后去判斷里面的文檔符合該filter與否,這個匹配的結果我們就可以用bitset來存儲起來,下次同樣的filter查詢過來,我們就直接使用內存里面的bitset來進行判斷就行了,而不需要再打開lucene的segment文件了,避免了io的操作,這樣就可以大大提高查詢處理的速度,這也是為什么filter這么高效的原因。
因為lucene的segment段文件是不變的,lucene會產生新段,但是舊段是不變的,所以bitset是重復利用的,根據不同的filter條件和不同的段,會產生相應的bitset,另外不同的查詢可能會涉及到多個bitset的做交集,計算機對這種bit位處理過程是非常拿手的,速度很快。
另外,如果filter的結果如果是空的,那么里面的bitset位都是0,es以后在處理該filter的時候,會把該bitset整個忽略掉,提高性能。
前面說完了基礎內容,咱們再看看bool filter和AND filter這些的區別吧
bool filter會使用到前面提到過的bitset數據結構(bitset派),而AND \OR\ NOTfilter則不能利用到bitset(non-bitset派),為什么呢?
AND、OR、NOT filter是doc by doc的逐個文檔的處理,es逐個加載文檔里面的字段內容,然后檢查字段的內容是否滿足查詢條件,不滿足的文檔就排除在結果集之外,依次迭代進行,直到過完一遍所有的文檔,這中間的過程用不到前面提到過的bitset,也就不能重復利用緩存資源
如果你有多個filter條件,即一個AND、OR、NOT里面包含多個filter過濾條件(支持數組的方式),那么處理的邏輯就是每個filter會將依次將生成的結果集傳到下一個filter,理論上處理的文檔數會越來越少,因為只會過濾減少,不會增加,這樣依次過濾,所以一般限制條件比較苛刻的可以放前面執行,這樣后面的filter需要處理的文檔數就會很小,這樣可以大大提高整體處理的速度,另外除了數量上的考慮外,還需要考慮filter的效率問題,一些filter執行效率很低,如Geo filter(大量計算)或者script based filter(動態腳本),建議將這些性能開銷比較大的查詢放最后執行來提高整體的處理速度。
好了,現在應該有這么一個概念了,AND、OR、NOT是文檔by文檔,依次處理,如果你的結果集很大,即一個很寬松的查詢,命中很多,那么你使用AND、OR、NOT filter是不合適的,但是有些filter是必須文檔by文檔處理的,如下面的這幾個filter:
- Geo* filters
- Scripts
- Numeric_range
所以除了上面那幾個沒有辦法的,其它的filter應該一律使用bool filter來提高查詢性能。
如果你的查詢里面需要同時使用到bitset和non-bitset類型的filter,則可以組合起來使用bool filter和AND\OR\NOT filter,
前面說了,AND 是結果集依次向后傳遞,所以我們把性能比較好的放前面,non-bitset放AND的filter的后面,如下面一個包含多個filter類型的復雜的filter
{ "and" : [ { "bool" : { "must" : [ { "term" : {} }, { "range" : {} }, { "term" : {} } ] } }, { "or" : [ { "custom_script" : {} }, { "geo_distance" : {} } ] } ] }
and 在最外層做wrapper,第一個filter是一個bool filter,里面有3個must的子filter,處理完了之后,得到文檔結果集,然后再執行一個or的子filter,OR里面兩個查詢會分別進行,最終的文檔結果集就是我們的搜索結果了。
總之,filter使用的時候,一定要優先使用bitset流,然后還要考慮filter順序和組合的問題
- Geo, Script or Numeric_range filter: 使用 And/Or/Not Filters
- 所有其它的: 使用 Bool Filter
掌握了以上這些,就不難寫出高性能的查詢了。
本文出自:http://log.medcl.net/item/2013/09/elasticsearch-inside-the-various-filter/