CONAN ZONE

          你越掙扎我就越興奮

          BlogJava 首頁 新隨筆 聯(lián)系 聚合 管理
            0 Posts :: 282 Stories :: 0 Comments :: 0 Trackbacks
          本文將介紹Solr查詢中涉及到的Cache使用及相關(guān)的實(shí)現(xiàn)。Solr查詢的核心類就是SolrIndexSearcher,

          每個(gè)core通常在 同一時(shí)刻只由當(dāng)前的SolrIndexSearcher供上層的handler使用

          (當(dāng)切換SolrIndexSearcher時(shí)可能會(huì)有兩個(gè)同時(shí)提供服務(wù)),而Solr的各種Cache是依附于SolrIndexSearcher的,SolrIndexSearcher在則Cache 生,SolrIndexSearcher亡則Cache被清空close掉。

          Solr中的應(yīng)用Cache有filterCache、 queryResultCache、documentCache等,這些Cache都是SolrCache的實(shí)現(xiàn)類,

          并且是 SolrIndexSearcher的成員變量,各自有著不同的邏輯和使命,下面分別予以介紹和分析。

          1、SolrCache接口實(shí)現(xiàn)類

          Solr提供了兩種SolrCache接口實(shí)現(xiàn)類:solr.search.LRUCache和solr.search.FastLRUCache。

          FastLRUCache是1.4版本中引入的,其速度在普遍意義上要比LRUCache更fast些。
          下面是對(duì)SolrCache接口主要方法的注釋:

          public interface SolrCache{publicObjectinit(Mapargs,Objectpersistence, CacheRegenerator regenerator);
          publicintsize();
          publicObjectput(Objectkey,Objectvalue);
          publicObjectget(Objectkey);publicvoidclear();voidwarm(SolrIndexSearcher searcher, SolrCache old)throwsIOException;
          publicvoidclose();}

          1.1、solr.search.LRUCache

          LRUCache可配置參數(shù)如下:

          1)size:cache中可保存的最大的項(xiàng)數(shù),默認(rèn)是1024
          2)initialSize:cache初始化時(shí)的大小,默認(rèn)是1024。
          3)autowarmCount:
          當(dāng)切換SolrIndexSearcher時(shí),可以對(duì)新生成的SolrIndexSearcher做autowarm(預(yù)熱)處理。
          autowarmCount表示從舊的SolrIndexSearcher中取多少項(xiàng)來在新的SolrIndexSearcher中被重新生成,

          如何重新生成由CacheRegenerator實(shí)現(xiàn)。在當(dāng)前的1.4版本的Solr中,這個(gè)autowarmCount只能取預(yù)熱的項(xiàng)數(shù),

          將來的4.0版本可以指定為已有cache項(xiàng)數(shù)的百分比,以便能更好的平衡autowarm的開銷及效果。

          如果不指定該參數(shù),則表示不做autowarm處理。實(shí)現(xiàn)上,LRUCache直接使用LinkedHashMap來緩存數(shù)據(jù),

          由initialSize來限定cache的大小,淘汰策略也是使用LinkedHashMap的內(nèi)置的LRU方式,

          讀寫操作都是對(duì)map的全局鎖,所以并發(fā)性效果方面稍差。

          1.2、solr.search.FastLRUCache

          在配置方面,F(xiàn)astLRUCache除了需要LRUCache的參數(shù),還可有選擇性的指定下面的參數(shù):

          1)minSize:當(dāng)cache達(dá)到它的最大數(shù),淘汰策略使其降到minSize大小,默認(rèn)是0.9*size。
          2)acceptableSize:當(dāng)淘汰數(shù)據(jù)時(shí),期望能降到minSize,但可能會(huì)做不到,則可勉為其難的降到acceptableSize,

          默認(rèn)是0.95*size。

          3)cleanupThread:相比LRUCache是在put操作中同步進(jìn)行淘汰工作,F(xiàn)astLRUCache可選擇由獨(dú)立的線程來做,

          也就是配置cleanupThread的時(shí)候。當(dāng)cache大小很大時(shí),每一次的淘汰數(shù)據(jù)就可能會(huì)花費(fèi)較長時(shí)間,

          這對(duì)于提供查詢請求的線程來說就不太合適,由獨(dú)立的后臺(tái)線程來做就很有必要。實(shí)現(xiàn)上,

          FastLRUCache內(nèi)部使用了ConcurrentLRUCache來緩存數(shù)據(jù),它是個(gè)加了LRU淘汰策略的ConcurrentHashMap,

          所以其并發(fā)性要好很多,這也是多數(shù)Java版Cache的極典型實(shí)現(xiàn)。

          2、filterCache

          filterCache存儲(chǔ)了無序的lucene document id集合,該cache有3種用途:

          1)filterCache
          存儲(chǔ)了filter queries(“fq”參數(shù))得到的document id集合結(jié)果。Solr中的query參數(shù)有兩種,即q和fq。如果fq存在,

          Solr是先查詢fq(因?yàn)閒q可以多個(gè),所以多個(gè)fq查詢是個(gè)取結(jié)果交集 的過程),之后將fq結(jié)果和q結(jié)果取并。

          在這一過程中,filterCache就是key為單個(gè)fq(類型為Query),value為documentid集合(類型為DocSet)的cache。

          對(duì)于fq為range query來說,filterCache表現(xiàn)出其有價(jià)值的一面。
          2)filterCache
          還可用于facet查詢(http://wiki.apache.org/solr/SolrFacetingOverview),facet查詢中各
          facet的計(jì)數(shù)是通過對(duì)滿足query條件的document
          id集合(可涉及到filterCache)的處理得到的。因?yàn)榻y(tǒng)計(jì)各facet計(jì)數(shù)可能會(huì)涉及到所有的doc
          id,所以filterCache的大小需要能容下索引的文檔數(shù)。
          3)如果solfconfig.xml中配置了<useFilterForSortedQuery/>,

          那么如果查詢有filter(此filter是一需要過濾的DocSet,而不是fq,我未見得它有什么用),

          則使用filterCache。

          下面是filterCache的配置示例:

          <!-- Internal cache used by SolrIndexSearcher for filters (DocSets),unordered sets of *all* documents
          that match a query.When a new searcher is opened, its caches may be prepopulatedor "autowarmed"
           using data from caches in the old searcher.autowarmCount is the number of items to prepopulate.
          For LRUCache,the prepopulated items will be the most recently accessed items.-->
          <filterCacheclass="solr.LRUCache"size="16384"initialSize="4096"/>

          對(duì)于是否使用filterCache及如何配置filterCache大小,需要根據(jù)應(yīng)用特點(diǎn)、統(tǒng)計(jì)、效果、經(jīng)驗(yàn)等各方面來評(píng)估。

          對(duì)于使用fq、facet的應(yīng)用,對(duì)filterCache的調(diào)優(yōu)是很有必要的。

          3、queryResultCache

          顧名思義,queryResultCache是對(duì)查詢結(jié)果的緩存(SolrIndexSearcher中的cache緩存的都是document id set),
          這個(gè)結(jié)果就是針對(duì)查詢條件的完全有序的結(jié)果。 下面是它的配置示例:
          <!-- queryResultCache caches results of searches - ordered lists ofdocument ids (DocList) based on a query, a sort, and the rangeof documents requested.-->
          <queryResultCacheclass="solr.LRUCache"size="16384"initialSize="4096"/>
          
          緩存的key是個(gè)什么結(jié)構(gòu)呢?就是下面的類(key的hashcode就是QueryResultKey的成員變量hc):
          publicQueryResultKey(Query query, List<Query>filters, Sort sort,intnc_flags)
          {
          this.query=query;
          this.sort=sort;
          this.filters=filters;
          this.nc_flags=nc_flags;
          inth=query.hashCode();
          if(filters!=null)h^=filters.hashCode();
          sfields=(this.sort!=null)?this.sort.getSort():defaultSort;
          for(SortField sf:sfields)
          { // mix the bits so that sortFields are position dependent
          // so that a,b won't hash to the same value as b,ah^=(h<<8)|(h>>>25);
          // reversible hashif(sf.getField()!=null)h+=sf.getField().hashCode();h+=sf.getType();
          if(sf.getReverse())h=~h;if(sf.getLocale()!=null)h+=sf.getLocale().hashCode();
          if(sf.getFactory()!=null)h+=sf.getFactory().hashCode();}hc=h;
          }
          因?yàn)椴樵儏?shù)是有start和rows的,所以某個(gè)QueryResultKey可能命中了cache,但start和rows卻不在cache的
          document id set范圍內(nèi)。當(dāng)然,document id
          set是越大命中的概率越大,但這也會(huì)很浪費(fèi)內(nèi)存,這就需要個(gè)參數(shù):queryResultWindowSize來指定document id
          set的大小。Solr中默認(rèn)取值為50,可配置,WIKI上的解釋很深簡單明了:
          <!-- An optimization for use with the queryResultCache. When a searchis requested, a superset of the requested number
          of document idsare collected.  For example, of a search for a particular queryrequests matching documents 10 
          through 19, and queryWindowSize is 50,then documents 0 through 50 will be collected and cached.
          Any furtherrequests in that range can be satisfied via the cache.-->
          <queryResultWindowSize>50</queryResultWindowSize>
          相比filterCache來說,queryResultCache內(nèi)存使用上要更少一些,但它的效果如何就很難說。
          就索引數(shù)據(jù)來說,通常我們只是在索引上存儲(chǔ)應(yīng)用主鍵id,再從數(shù)據(jù)庫等數(shù)據(jù)源獲取其他需要的字段。
          這使得查詢過程變成,首先通過solr得到document id set,再由Solr得到應(yīng)用id集合,
          最后從外部數(shù)據(jù)源得到完成的查詢結(jié)果。如果對(duì)查詢結(jié)果正確性沒有苛刻的要求,可以在Solr之外獨(dú)立的緩存完整的

          查詢結(jié)果(定時(shí)作廢),這時(shí)queryResultCache就不是很有必要,否則可以考慮使用queryResultCache。當(dāng)然,如果發(fā)現(xiàn)在
          queryResultCache生命周期內(nèi),query重合度很低,也不是很有必要開著它。

          4、documentCache

          又顧名思義,documentCache用來保存<doc_id,document>對(duì)的。如果使用documentCache,就盡可能開大

          些,至少要大過<max_results> *<max_concurrent_queries>,否則因?yàn)閏ache的淘汰,
          一次請求期間還需要重新獲取document一次。也要注意document中存儲(chǔ)的字段的多少,避免大量的內(nèi)存消耗。
          下面是documentCache的配置示例:<!-- documentCache caches Lucene Document objects (the stored fields for each document).-->
          <documentCacheclass="solr.LRUCache"size="16384"initialSize="16384"/>
          
          5、User/Generic Caches 
          Solr支持自定義Cache,只需要實(shí)現(xiàn)自定義的regenerator即可,下面是配置示例:<!-- Example of a generic cache. These caches may be accessed by namethrough SolrIndexSearcher.getCache(),
          cacheLookup(), and cacheInsert().The purpose is to enable easy caching of user/application level data.
          The regenerator argument should be specified as an implementationof solr.search.CacheRegenerator if
           autowarming is desired.--><!--<cache name="yourCacheNameHere"class="solr.LRUCache"size="4096"
          initialSize="2048"regenerator="org.foo.bar.YourRegenerator"/>-->
          6、The Lucene FieldCache 
          lucene中有相對(duì)低級(jí)別的FieldCache,Solr并不對(duì)它做管理,所以,lucene的FieldCache還是由lucene的IndexSearcher來搞。

          7、autowarm

          上面有提到autowarm,autowarm觸發(fā)的時(shí)機(jī)有兩個(gè),一個(gè)是創(chuàng)建第一個(gè)Searcher時(shí)(firstSearcher),一個(gè)是創(chuàng)建個(gè)新

          Searcher(newSearcher)來代替當(dāng)前的Searcher。在Searcher提供請求服務(wù)前,Searcher中的各個(gè)Cache可以
          做warm處理,處理的地方通常是SolrCache的init方法,而不同cache的warm策略也不一樣。
          1)filterCache:filterCache注冊了下面的CacheRegenerator,就是由舊的key查詢索引得到新值put到新cache中。solrConfig.filterCacheConfig.setRegenerator(newCacheRegenerator(){publicbooleanregenerateItem
          (SolrIndexSearcher newSearcher, SolrCache newCache, SolrCache oldCache,ObjectoldKey,ObjectoldVal)
          throwsIOException{newSearcher.cacheDocSet((Query)oldKey,null,false);returntrue;}});
          2)queryResultCache:queryResultCache的autowarm不在SolrCache的init(也就是說,不是去遍歷已
          有的queryResultCache中的query key執(zhí)行查詢),而是通過SolrEventListener接口的void
          newSearcher(SolrIndexSearcher newSearcher, SolrIndexSearcher
          currentSearcher)方法,來執(zhí)行配置中特定的query查詢,達(dá)到顯示的預(yù)熱lucene FieldCache的效果。
          queryResultCache的配置示例如下:
          <listenerevent="newSearcher"class="solr.QuerySenderListener"><arrname="queries"><!-- seed common sort fields --><lst>
          <strname="q">anything</str><strname="sort">name desc price desc populartiy desc</str></lst></arr>
          </listener><listenerevent="firstSearcher"class="solr.QuerySenderListener"><arrname="queries">
          <!-- seed common sort fields --><lst><strname="q">anything</str><strname="sort">
          name desc, price desc, populartiy desc</str></lst><!-- seed common facets and filter queries -->
          <lst><strname="q">anything</str><strname="facet.field">category</str>
          <strname="fq">inStock:true</str><strname="fq">price:[0 TO 100]</str></lst></arr></listener>
          3)documentCache:因?yàn)樾滤饕膁ocument id和索引文檔的對(duì)應(yīng)關(guān)系發(fā)生變化,所以documentCache沒有warm的過程,
          落得白茫茫一片真干凈。盡管autowarm很好,也要注意autowarm帶來的開銷,這需要在實(shí)際中檢驗(yàn)其warm的開銷,
          也要注意Searcher的切換頻率,避免因?yàn)閣arm和切換影響Searcher提供正常的查詢服務(wù)。

          8、參考文章
          http://wiki.apache.org/solr/SolrCaching
          posted on 2012-06-13 14:12 CONAN 閱讀(1872) 評(píng)論(0)  編輯  收藏 所屬分類: Solr
          主站蜘蛛池模板: 边坝县| 雅江县| 东光县| 合阳县| 什邡市| 成安县| 兴业县| 淳化县| 房山区| 班玛县| 囊谦县| 北宁市| 临江市| 阳城县| 二手房| 扎鲁特旗| 化德县| 体育| 思南县| 武胜县| 岳池县| 南京市| 南木林县| 礼泉县| 博兴县| 吐鲁番市| 沅江市| 新竹市| 鄄城县| 罗平县| 南涧| 浠水县| 荥经县| 天津市| 长岭县| 宜昌市| 喀什市| 子洲县| 陕西省| 屯昌县| 田林县|