首先來看看filter的接口定義:
public abstract class Filter implements java.io.Serializable {
public abstract BitSet bits(IndexReader reader) throws IOException;
} 前端
簡單明瞭從reader中知道哪些記錄是能夠讀出來的用true false放在bitsets中,而後再用這去和總集合作and操做獲得剩餘記錄數,而後再經過query查詢.原理知道了,下面來考慮下它的緩存:
緩存filter自己,因爲他是序列化對象,那麼已經具有了緩存的條件,可是這是一個錯誤,由於你緩存了這個類,而當你把參數reader拿出來依然會和機器產生io,所以這是極其不恰當的方法,應該緩存它的結果.
在lucene中有這麼幾個和filter有關的類:
CachingWrapperFilter
CachingSpanFilter
RemoteCachingWrapperFilter
FilterManager java
其實我想質疑前兩個,爲何呢,請看他的源碼:
protected transient Map cache; nginx
他放置緩存的map竟然是transient的,這意味着即便你把它實例在static中這個變量依然會每次要new的,這樣的緩存有意義嗎?我看不出他怎麼緩存的
/**
* A transient Filter cache. To cache Filters even when using {@link org.apache.lucene.search.RemoteSearchable} use
* {@link org.apache.lucene.search.RemoteCachingWrapperFilter} instead.
*/
上面這句註釋總算明瞭了,呵呵.
那麼其實RemoteCachingWrapperFilter纔是真正的cache類,他的實現藉助於filterManager,這個類是咱們平時能理解的那種cache結構
public BitSet bits(IndexReader reader) throws IOException {
Filter cachedFilter = FilterManager.getInstance().getFilter(filter);
return cachedFilter.bits(reader);
} 數據庫
但這個還不夠,第一他的性能我內心沒譜,遇到上萬的訪問怎麼辦?因此仍是要用第三方的緩存,我使用的是memcached,這個東西不介紹了,只有一個問題,就是必需要求對象是可序列化的,這個不難理解,要想網絡傳輸只能治麼搞.
個人緩存策略:把最細胞的filter用memached緩存他的結果集,而他的組合fliter用自帶的filtermanager管理就行了. apache
而我這樣的道理也是基於filtermanager的key是reader的hashcode,所以他是對應不一樣的索引的.那麼確定有朋友問怎麼刷新呢?太簡單了啊,你的key只要有reader或者search的hashcode就能夠了,你一旦更新的源hashcode就變化了.(若是你的search和reader的hash不是固定的那麼你確定承受不了100以上的並行訪問,io會高得驚人.) 緩存
另一個技巧,是關於rangefilter的,這個東西不錯,可是有一點難,在哪裏呢?由於他的查詢彷佛效率不高,所以必定要緩存! 可是key呢?好比我經常使用的key是timestamp,可是實際中就會發現若是用毫秒的timestamp那麼key幾乎無用,由於不多相同的,通過改進,我把時間能夠用月作單位,查詢也是如此,若是你的要求高我以爲作到天就ok了,若是你數據再多用到小時確定也夠了吧,這樣filter的緩存會帶來極大的性能提高. 服務器
那麼實際效果呢,在原來使用時候2臺集羣機(nginx做爲前端代理,後部用resin做爲應用服務器)io平均1.xx 如今加了緩存以後常年保持在0.2左右!性能獲得了幾乎5~6倍的提高.而通常查詢一個十萬當量的+ 5個關鍵字 + 3個filter 時間大約是<10ms 非命中時大約是 70~80ms 這個速度若是獲得一樣結果的數據庫至少要放大1000倍的時間. 網絡
因爲我memcached沒有作集羣是獨立的(事實也應該如此,由於你兩臺機器的reader的hashcode確定是不同的,放一塊兒也是這樣的結果,這樣也沒有很差,當一臺機器出現問題或者須要更新代碼能夠用時間差來保證負荷平穩過渡,不像之前一臺機器每次重啓都是有點怕怕的,只能找空閒時間纔敢這麼作. app
最後要講的query,其實前面我說了半天沒有提到query,query的緩存呢? 其實在lucene中有這麼個類:
QueryFilter
這個類簡單說就是把query變成filter,那幹什麼呢?很簡單啊,這樣任何查詢都會變成filter的,因此全部的緩存都是filter!那麼從緩存中取出來的filterquery怎麼用? memcached
MatchAllDocsQuery matchAll = new MatchAllDocsQuery(); result = isearch.search(matchAll, filter, sort); filter是用個人合成filter組合的,這樣消耗就更低了,固然不建議無限制增長系統負荷,由於那樣就幾乎沒法重啓了,呵呵.好了基本說到這裏,其實最後我想說個人核心思想: 任何query都是filter,lucene就是filter查詢,事實是如此的,呵呵.