Elasticsearch2.x Filter執行流程及緩存原理


一、基本概念

這里說的Filter非Post filter,關於Post filter這里不做介紹,我們主要關注的是在執行一個評分查詢前執行的Filter。

在講述ES Filter的執行流程和緩存原理之前,有幾個概念我們必須要清楚。

Query and Filter context 

官網地址:https://www.elastic.co/guide/en/elasticsearch/reference/current/query-filter-context.html

1. Query Context

所謂查詢上下文,是指包含一個或多個查詢條件的邏輯組合,QueryContext里包含的的單個查詢表示的含義是“文檔和該查詢條件的匹配度有多大”,針對QueryContext里的每一個查詢都會計算出一個_score來表示匹配度,整個QueryContext的匹配度評分等於其包含所有單個查詢評分的總和,所以針對一個Query我們更多關注的是匹配度。

2.Filter Context

過濾器上下文和查詢上下文類似,都是由1個或多個子查詢(Query clause) 組成的。他們的區別在於Filter不會計算文檔得分,它代表的含義是“文檔和該查詢條件是否匹配”,所以針對一個Filter我們更多關注的是能否可以過濾掉文檔,返回的結果只能是可以或者不可以(true or false)。

二、基本查詢

在寫基本查詢前我們先創建一個索引(my_store)和一個類型(products)並插入4條product數據

 

[java] view plain copy
 
  1. curl -XPUT http://localhost:9200/my_store  
  2. curl -XPOST http://localhost:9200/my_store/products/_mapping -d '  
  3. {  
  4.     "products": {  
  5.         "properties": {  
  6.             "productID": {  
  7.                 "type": "string",  
  8.                 "index": "not_analyzed"  
  9.             },  
  10.             "price": {  
  11.                 "type": "double"  
  12.             }  
  13.         }  
  14.     }  
  15. }'  
  16.   
  17. curl -XPOST http://localhost:9200/my_store/products/1 -d '{"productID":"XHDK-A-1293-#fJ3","price":10}'  
  18. curl -XPOST http://localhost:9200/my_store/products/2 -d '{"productID":"KDKE-B-9947-#kL5","price":20}'  
  19. curl -XPOST http://localhost:9200/my_store/products/3 -d '{"productID":"JODL-X-1937-#pV7","price":30}'  
  20. curl -XPOST http://localhost:9200/my_store/products/4 -d '{"productID":"QQPX-R-3956-#aD8","price":40}'  

插入數據后通過head插件看到的數據如下

 


要執行一個基於過濾器的查詢必須要用bool query這樣才能把過濾器嵌入到查詢中,一個bool query的DLS基本格式是這樣的

 

[java] view plain copy
 
  1. {  
  2.   "query": {  
  3.     "bool": {  
  4.       "must": {...},  
  5.       "must_not": {...},  
  6.       "should": {...},  
  7.       "filter": {...}  
  8.     }  
  9.   }  
  10. }  

當存在Filter這一項時,其他3項(must,must_not,should)是可選的,如果不傳將默認match_all。

 

在執行上面這個查詢時,Filter會優先於其他項執行,其他的Query會在過濾器執行的結果集中再執行,這樣可以在真正執行評分查詢前過濾掉大部分數據,這也正是過濾器的主要功能。下面的例子是查詢productID等於“XHDK-A-1293-#fJ3”的DLS

 

[java] view plain copy
 
  1. {  
  2.   "query": {  
  3.     "bool": {  
  4.       "filter": {  
  5.         "term": {  
  6.           "productID": "XHDK-A-1293-#fJ3"  
  7.         }  
  8.       }  
  9.     }  
  10.   }  
  11. }  

這個查詢我們只指定Filter這一項,所以返回的結果就是filter過濾后的結果且未執行文檔評分。

 

三、Filter執行流程

下面的截圖是官網對Filter執行流程的描述

官網地址:https://www.elastic.co/guide/en/elasticsearch/guide/current/_finding_exact_values.html#_finding_exact_values

 

這里先簡單的翻譯下,ES在執行非評分查詢(這里的非評分查詢我們以上面TermQuery查詢為例)時會依次執行以下幾個操作

1.查找匹配文檔

TermQuery先在倒排索引中匹配到符合指定查詢值的文檔列表,這個case中是查詢值是productID=XHDK-A-1293-#fJ3的文檔也就是_id=1的文檔。

2.創建一個bitset(位圖)

Filter根據第1步的查詢結果創建一個位圖(一個只包含0和1的數組) ,用來表示文檔是否被包含在這個TermQuery中,在我們的例子中這個bitset是[1,0,0,0]  它表示第1個文檔匹配,第2、3.、4不匹配。在ES內部該位圖采用“roaring bitmap”算法進行位圖壓縮,它能夠高效的壓縮稀疏和稠密集合。想深入了解的同學請自行google。

3.迭代生成的位圖

在多個TermQuery同時存在一個FilterContext 中執行過濾查詢時,會生成多個位圖(一個Query clause對應一個BitSet),ES會迭代這些位圖並從中找到符合條件的文檔。當然ES會很智能的選擇位圖的執行順序,通常情況下ES會選擇稀疏的位圖優先執行,這樣的做的目的是過濾掉大部分不符合條件的文檔。

4.疊加Bitset的執行次數

ES能緩存非評分查詢並快速訪問,但是它會很蠢的緩存一些不常使用的東東,在倒排索引中非評分查詢已經相當快了,所以我們需要緩存那些“我們知道會在接下來的時間被多次訪問的查詢” 以免造成資源浪費。

為了這樣做,ES跟蹤記錄了以每個索引為基礎的歷史訪問記錄,如果一個查詢在最近的256個查詢中被執行了若干次,那么它將會被緩存到內存中(一個非評分查詢被緩存實際上是該查詢的位圖被緩存),當位圖被緩存時還有兩個條件是要滿足的:該查詢對應的segments所持有的文檔數必須大於1W 且必須大於總索引大小的3%,ES這樣做是因為對於那些小的索引段會很快的被合並掉,對它們的緩存其實是一種浪費

 

上面的流程可能看得不是很明白,下面我們舉一個實際的例子來說明下,看下面這個查詢。

 

[java] view plain copy
 
  1. {  
  2.   "from" : 0,  
  3.   "size" : 5,  
  4.   "query" : {  
  5.     "bool" : {  
  6.       "filter" : {  
  7.         "bool" : {  
  8.           "must" : [ {  
  9.             "term" : {  
  10.               "productID" : "JODL-X-1937-#pV7"  
  11.             }  
  12.           }, {  
  13.             "range" : {  
  14.               "price" : {  
  15.                 "from" : 20,  
  16.                 "to" : null,  
  17.                 "include_lower" : true,  
  18.                 "include_upper" : true  
  19.               }  
  20.             }  
  21.           } ]  
  22.         }  
  23.       }  
  24.     }  
  25.   }  
  26. }  

這個查詢中的Filter Context中包含2個Query clause,一個是term查詢,一個是range查詢。

 

第一步,根據term和range查詢得到兩個BitSet,這里應該是term -> [0,0,1,0]和range ->  [0,1,1,1]

第二步,合並兩個BitSet:[0,0,1,0] +  [0,1,1,1] = [0,0,1,0],合並到可以看出只有第3個文檔符合條件,返回查詢結果

第三步,分別緩存term和range查詢生成的Bitset,以便其他查詢包含這兩個query clause的時候可以直接從緩存讀取,以后每次命中緩存都會對對應的BiSet調用次數+1

四、Filter Cache(Query Cache)

這里的過濾器緩存其實指的就是我們所了解的查詢緩存(非Query Request緩存),下面是官網對Query Cache的描述

官網地址:https://www.elastic.co/guide/en/elasticsearch/reference/current/query-cache.html

 

上面描述的以及之前討論過的的可以簡單把Query Cache總結為以下幾點

1.  Query Cache是節點級別的,每個節點上的所有分片共享一份緩存

2.  Query Cache采用LRU緩存失效策略

3.  Query Cache只能在Filter Context中被使用

4.  Query Cache可以通過 indices.queries.cache.size來設置緩存占用大小,默認10%,可手動設置比如512mb

5.  Query Cache實際緩存的是Bitset(位圖),一個Query clause對應一個Bitset

6.  緩存要生效,必須滿足兩個條件

        a)查詢對應的segments所持有的文檔數必須大於10000

        b)查詢對應的segments所持有的文檔數必須大於整個索引size的3%

7.  當新索引文檔時,Query Cache不會重新計算,而是判斷索引的文檔是否符合緩存對應的Query clause,滿足則加入BitSet中

 

轉自:http://blog.csdn.net/chennanymy/article/details/52403594


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM