什么是filtercache?
solr應用中為了提高查詢速度有可以利用幾種cache來優化查詢速度,分別是fieldValueCache,queryResultCache,documentCache,filtercache,在日常使用中最為立竿見影,最有效的應屬filtercache,何謂filtercache?這個需要從一段solr的查詢日志開始說起,下面是我截取的solr運行中打印的一段查詢日志:
[search4alive-0] Request_is ==> q=status%3A0++AND+biz_type%3A2+AND+class_id%3A1&sort=index_sort_order+desc&start=0&rows=5,queryTime_is ==> 2 [search4alive-0] Request_is ==> q=status%3A0++AND+biz_type%3A1+AND+class_id%3A1+AND+%28group_id%3A411%29&sort=gmt_create+desc&start=0&rows=20,queryTime_is ==> 2 [search4alive-0] Request_is ==> q=status%3A0++AND+biz_type%3A2+AND+class_id%3A1&sort=index_sort_order+desc&start=0&rows=5,queryTime_is ==> 2 [search4alive-0] Request_is ==> q=status%3A0++AND+biz_type%3A1+AND+class_id%3A1+AND+%28group_id%3A8059%29&sort=gmt_create+desc&start=0&rows=20,queryTime_is ==> 0 [search4alive-0] Request_is ==> debugQuery=on&group=true&group.field=group_id&group.ngroups=true&group.sort=gmt_create+desc&q=status%3A0++AND+biz_type%3A1+AND+class_id%3A1+AND+ha [search4alive-0] Request_is ==> q=status%3A0++AND+biz_type%3A2+AND+class_id%3A1&sort=index_sort_order+desc&start=30&rows=30,queryTime_is ==> 4 [search4alive-0] Request_is ==> q=status%3A0++AND+biz_type%3A2+AND+class_id%3A1&sort=index_sort_order+desc&start=0&rows=5,queryTime_is ==> 1 [search4alive-0] Request_is ==> q=status%3A0++AND+biz_type%3A1+AND+class_id%3A1+AND+%28group_id%3A375%29&sort=gmt_create+desc&start=0&rows=20,queryTime_is ==> 3 [search4alive-0] Request_is ==> q=status%3A0++AND+biz_type%3A2+AND+class_id%3A1&sort=index_sort_order+desc&start=0&rows=5,queryTime_is ==> 1 [search4alive-0] Request_is ==> q=status%3A0++AND+biz_type%3A2+AND+class_id%3A1&sort=index_sort_order+desc&start=0&rows=30,queryTime_is ==> 4 [search4alive-0] Request_is ==> q=status%3A0++AND+biz_type%3A2+AND+class_id%3A1&sort=index_sort_order+desc&start=0&rows=5,queryTime_is ==> 1 [search4alive-0] Request_is ==> q=status%3A0++AND+biz_type%3A2+AND+class_id%3A1&sort=index_sort_order+desc&start=0&rows=30,queryTime_is ==> 4 [search4alive-0] Request_is ==> q=status%3A0++AND+biz_type%3A2+AND+class_id%3A1&sort=index_sort_order+desc&start=0&rows=30,queryTime_is ==> 3
看到這段查詢日志之后,我們開始考慮如何提升查詢的rt(查詢速度),因為在參數q中的查詢是要有磁盤IO開銷的,很自然的思路是將整個查詢的參數q作為key,對應的結果作為value,這樣做是可以的,但是查詢的命中率會很低,會占用大量內存空間。
查詢參數q上基本上每次都會出現status,biz_type,class_id 對於這樣的字查詢,所以可以把整個查詢條件分成兩部分一部分是以status,biz_type,class_id 這幾個條件組成的子查詢條件,另外一部分是除這三個條件之外的子查詢。在進程查詢的時候,先將status,biz_type,class_id 條件組成的條件作為key,對應的結果作為value進行緩存,然后再和另外一部分查詢的結果進行求交運算。
![]() |
通過上面這幅圖明白了filtercache的意義是,將原先一個普通查詢分割成兩個組合查詢的與運算,兩個子查詢至少有一個使用緩存,這樣既減少了查詢過程的IO操作,又控制了緩存的容量不會消耗過多的內存。
如何使用?
首先要配置solrconfig.xml 要開啟fltercache:
- <query>
- <filterCache class="solr.LRUCache" size="50000" initialSize="512" autowarmCount="0"/>
- </query>
這里使用的是solr實現的基於LRU算法的緩實現,以上配置是使用solr.LRUCache ,使用這個cache在插入多,查詢少的情況比較使用,如果是查詢多,插入少的情況,可以使用solr.FastLRUCache緩存模塊。
客戶端API調用:
下面是原先的客戶端端查詢代碼:
- SolrQuery query = new SolrQuery();
- query.setQuery("status:0 AND biz_type:1 AND class_id:1 AND xxx:123");
- QueryResponse response = qyeryServer.query(query);
使用filterQuery之后的查詢代碼:
- SolrQuery query = new SolrQuery();
- query.addFilterQuery("status:0 AND biz_type:1 AND class_id:1");
- query.setQuery("xxx:123");
- QueryResponse response = qyeryServer.query(query);
經過測試這樣優化之后,查詢的RT(查詢速度)會明顯減小,QPS(每秒查詢率)會有明顯提升。
使用filterquery過程中需要注意點:
●不能在filterQuery 上重復出現query中的查詢參數,如果上面的filterquery調用方法如下所示:
- query.addFilterQuery("status:0 AND biz_type:1 AND class_id:1 AND xxx:123");
- query.setQuery("xxx:123");
如上,條件xxx:123 在filterQuery和query上都出現了,這樣的寫法非但起不到查詢優化的目的,而且還會增加查詢的性能開銷。
●盡量減少調用addFilterQuery方法的次數
- query.addFilterQuery("status:0 ");
- query.addFilterQuery("biz_type:1 ");
- query.addFilterQuery("class_id:1 ");
- query.setQuery("xxx:123");
如上,將status:0 AND biz_type:1 AND class_id:1 這個組合查詢條件,分三次調用filterQuery方法來完成,這樣的調用方法雖然是正確的,並且能起到性能優化的效果,優化性能沒有調用一次addFilterQuery方法來得高,原因是多調用了兩次addFilterQuery,就意味着最后需要多進行兩次結果集的求交運算,雖然結果集求交運算速度很快,但畢竟是有性能損耗的。
不過從內存開銷的角度來說,調用三次addfilterQuery方法這樣可以有效降低內存的使用量,這個是肯定的。所以在是否調用多次addFilterQuery方法的原則是,在內存開銷允許的前提下,將量將所有filterQuery條件,通過調用有限次數的addFilterQuery方法來完成。
下文摘自solr中國
What it is used for?
先從內部機制開始。FilterCache存儲了一些無序的文檔標識號(ID)。這些ID並不是我們在schema.xml里配置的unique key,而是solr內部的一個文檔標識。請記住這個。
FilterCache的任務是保持與用戶過濾的結果關聯。另外,cache可以輔助facet機制(在使用TermEnum時),在solrconfig.xml中的<useFilterForSortedQuery/>參數設為true時,還可以進行排序。
Definition
FilterCache的標准定義如下:
- <filterCache
- class=”solr.FastLRUCache”
- size=”16384″
- initialSize=”4096″
- autowarmCount=”4096″ />
有以下的配置可供選擇:
class:實現類。建議使用solr.FastLRUCache,它能在大量的GET、PUT操作下,提供更好的性能。
size:cache的最大值。
initialSize:cache的初始化值。
autowarmCount:從舊的cache到新的cache時,需要被復制的數量。
minSize:在full restoraton的情況下,將cache減小后的值
acceptableSize:如果minSize沒有設置,則該值會替代之
cleanupThread:默認false,如果設為true則會使用一個分離的topic來清理cache。
大部分情況下,設置initialSize和autowarmCount就已經足夠了。
How to configure?
cache的大小,需要根據基本的查詢語句而定;maximum大小應該至少等於我們使用的過濾字段的大小。舉個例子說明:如果在某個時間內,你的應用程序使用了2000個查詢參數,則minimum的大小應該最小設為2000。
Efficient use
然而,光有配置是不夠的,我們還需要讓查詢能夠使用它。請看下面的例子:
- q=name:solr+AND+category:ksiazka+AND+section:ksiazki
初看起來,查詢語句是正確的。但是有個問題:它並沒有用到filterCache。所有的請求將會綁定到queryResultCache中並創建一個單獨的條目。我們來作一下修改:
- q=name:solr&fq=category:ksiazka&fq=section:ksiazki
- 對應java代碼:
-
SolrQuery query = new SolrQuery();
-
query.addFilterQuery( "category:ksiazka");
-
query.addFilterQuery( "section:ksiazki");
-
query.setQuery( "name:solr");
-
-
QueryResponse response = qyeryServer.query(query);
-
有什么變化呢?在這個例子中,一個條目會寫入到queryResultCache中;另外,還會有兩個條目會寫入到filterCache中。現在看一下下面的語句:
- q=name:lucene&fq=category:ksiazka&fq=section:ksiazki
這個查詢會創建一個條目到queryResultCache中,但是會使用filterCache中兩個已經存在的條目。這樣查詢的執行時間會降低,IO的使用也會節省。
然而,對於下面的查詢:
- q=name:lucene+AND+category:ksiazka+AND+section:ksiazki
solr不能使用任何cache並且需要從lucene索引中收集所有的信息。
Last few words
就像你所看到的,配置cache 的正確方法不是如何保證solr能夠使用它,而是如何構建查詢語句來提升性能。當考慮查詢的時候,請考慮這一點。