一、基本概念
這里說的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)。
二、基本查詢
- curl -XPUT http://localhost:9200/my_store
- curl -XPOST http://localhost:9200/my_store/products/_mapping -d '
- {
- "products": {
- "properties": {
- "productID": {
- "type": "string",
- "index": "not_analyzed"
- },
- "price": {
- "type": "double"
- }
- }
- }
- }'
- curl -XPOST http://localhost:9200/my_store/products/1 -d '{"productID":"XHDK-A-1293-#fJ3","price":10}'
- curl -XPOST http://localhost:9200/my_store/products/2 -d '{"productID":"KDKE-B-9947-#kL5","price":20}'
- curl -XPOST http://localhost:9200/my_store/products/3 -d '{"productID":"JODL-X-1937-#pV7","price":30}'
- curl -XPOST http://localhost:9200/my_store/products/4 -d '{"productID":"QQPX-R-3956-#aD8","price":40}'
插入數據后通過head插件看到的數據如下
要執行一個基於過濾器的查詢必須要用bool query這樣才能把過濾器嵌入到查詢中,一個bool query的DLS基本格式是這樣的
- {
- "query": {
- "bool": {
- "must": {...},
- "must_not": {...},
- "should": {...},
- "filter": {...}
- }
- }
- }
當存在Filter這一項時,其他3項(must,must_not,should)是可選的,如果不傳將默認match_all。
在執行上面這個查詢時,Filter會優先於其他項執行,其他的Query會在過濾器執行的結果集中再執行,這樣可以在真正執行評分查詢前過濾掉大部分數據,這也正是過濾器的主要功能。下面的例子是查詢productID等於“XHDK-A-1293-#fJ3”的DLS
- {
- "query": {
- "bool": {
- "filter": {
- "term": {
- "productID": "XHDK-A-1293-#fJ3"
- }
- }
- }
- }
- }
這個查詢我們只指定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這樣做是因為對於那些小的索引段會很快的被合並掉,對它們的緩存其實是一種浪費
上面的流程可能看得不是很明白,下面我們舉一個實際的例子來說明下,看下面這個查詢。
- {
- "from" : 0,
- "size" : 5,
- "query" : {
- "bool" : {
- "filter" : {
- "bool" : {
- "must" : [ {
- "term" : {
- "productID" : "JODL-X-1937-#pV7"
- }
- }, {
- "range" : {
- "price" : {
- "from" : 20,
- "to" : null,
- "include_lower" : true,
- "include_upper" : true
- }
- }
- } ]
- }
- }
- }
- }
- }
這個查詢中的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