Solr簡(jiǎn)介
Solr是一個(gè)獨(dú)立的企業(yè)級(jí)搜索應(yīng)用服務(wù)器,它對(duì)外提供類似于Web-service的API接口。用戶可以通過(guò)http請(qǐng)求,向搜索引擎服務(wù)器提交一定格式的XML文件,生成索引;也可以通過(guò)Http Get操作提出查找請(qǐng)求,并得到XML格式的返回結(jié)果。
要想知道solr的實(shí)現(xiàn)原理,首先得了解什么是全文檢索,solr的索引創(chuàng)建過(guò)程和索引搜索過(guò)程。
全文檢索
首先舉個(gè)例子:比如現(xiàn)在有5個(gè)文檔,我現(xiàn)在想從5個(gè)文檔中查找出包含“solr工作原理”的文檔,此時(shí)有兩種做法:
1.順序掃描法:對(duì)5個(gè)文檔依次查找,包含目標(biāo)字段的文檔就記錄下來(lái),最后查找的結(jié)果可能是在2,3文檔中,這種查找方式叫做順序掃描法。
順序掃描法在文檔數(shù)量較少的情況下,查找速度還是很快的,但是當(dāng)文檔數(shù)量很多時(shí),查找速度就差強(qiáng)人意了。
2.全文檢索:對(duì)文檔內(nèi)容進(jìn)行分詞,對(duì)分詞后的結(jié)果創(chuàng)建索引,然后通過(guò)對(duì)索引進(jìn)行搜索的方式叫做全文檢索。
全文檢索就相當(dāng)于根據(jù)偏旁部首或者拼音去查找字典,在文檔很多的情況,這種查找速度肯定比你一個(gè)一個(gè)文檔查找要快。
solr中的cache的實(shí)現(xiàn)原理
搭建過(guò)solr的人肯定對(duì)solrconf.xml不陌生,在《query》《/query》中有多個(gè)cache,比如filterCache、queryResultCache,documentCache。這個(gè)博客就是介紹這三個(gè)cache的意思、配置以及他們的使用。
我們直接看代碼,對(duì)于這三個(gè)cache的使用是在solrIndexSearcher中,他有下面的屬性
private final boolean cachingEnabled;//這個(gè)indexSearcher是否使用緩存
private final SolrCache《Query,DocSet》 filterCache;對(duì)應(yīng)于filterCache
private final SolrCache《QueryResultKey,DocList》 queryResultCache;//對(duì)應(yīng)于queryResultCache
private final SolrCache《Integer,Document》 documentCache;//對(duì)應(yīng)于documentCache
private final SolrCache《String,UnInvertedField》 fieldValueCache;//這個(gè)稍后再說(shuō)
在SolrIndexSearcher的構(gòu)造方法中可以發(fā)現(xiàn)對(duì)上面的幾個(gè)cache的賦值:
通過(guò)上面的代碼可以發(fā)現(xiàn),如果在solrconf.xml中配置了對(duì)應(yīng)的cache,就會(huì)在solrIndexSearcher中創(chuàng)建對(duì)應(yīng)的cache。
solrconf.xml中cache的實(shí)現(xiàn)原理:
我們以《filterCache class=“solr.FastLRUCache” size=“512” initialSize=“512” autowarmCount=“0”/》這個(gè)為例:創(chuàng)建這個(gè)cache的實(shí)現(xiàn)類是FastLRUCache,他的實(shí)現(xiàn)原理就是封裝了concurrentHashMap,最大可以存放512個(gè)緩存的key,初始大小為512個(gè),autoWarmCount這個(gè)稍后再說(shuō)。在solr中默認(rèn)有兩個(gè)cache,一個(gè)是剛才說(shuō)的FastLRUCache,還有一個(gè)是LRUCache,他的實(shí)現(xiàn)原理是LinkedHashMap+同步,很明顯這個(gè)的性能要比前一個(gè)要差一些,所以可以將LRUCache都換為FastLRuCache。不過(guò)這兩個(gè)cahce都是基于lru算法的,貌似也不適合我們的需求,最好是lfu的,所以可以通過(guò)改變這些配置,使用一個(gè)基于lfu算法的cache,當(dāng)然這個(gè)不是這篇博客的內(nèi)容。我們先看一下這個(gè)FastLRUCache的實(shí)現(xiàn):
1、初始化cache的方法:
在FastLruCache中還有一些put,get,clear這些顯而易見(jiàn)的方法(對(duì)生成的ConcurrentLRUCache對(duì)象操作),另外還有一個(gè)warm方法比較重要,我專門在一篇博客中寫他的作用。
接下來(lái)我們進(jìn)入到ConcurrentLRUCache類中,看看他的實(shí)現(xiàn)。
再看一下他的添加方法:
看到這里就明白了solr自帶的緩存的實(shí)現(xiàn)原理了。(markAndSweep方法我沒(méi)有完全看懂,不過(guò)不影響我們的理解)
在緩存中還有一個(gè)重要的方法是獲得這個(gè)緩存的使用情況: public NamedList getStatistics() 方法,返回一個(gè)類似于map的結(jié)構(gòu),我們看看FastLRUCache的代碼:
public NamedList getStatistics() {
NamedList《Serializable》 lst = new SimpleOrderedMap《》();
if (cache == null) return lst;
ConcurrentLRUCache.Stats stats = cache.getStats();//這里的stats就是用來(lái)記錄緩存使用的情況的,比如大小,添加次數(shù),訪問(wèn)次數(shù)、查詢未命中次數(shù),驅(qū)逐次數(shù)。
long lookups = stats.getCumulativeLookups();//這個(gè)是查詢總的次數(shù),包括命中的次數(shù)+未命中的次數(shù)
long hits = stats.getCumulativeHits();//查詢的有效命中次數(shù)
long inserts = stats.getCumulativePuts();//添加緩存的次數(shù)
long evictions = stats.getCumulativeEvictions();//累計(jì)的驅(qū)逐次數(shù)
long size = stats.getCurrentSize();//大小
long clookups = 0;
long chits = 0;
long cinserts = 0;
long cevictions = 0;
// NOTE: It is safe to iterate on a CopyOnWriteArrayList
for (ConcurrentLRUCache.Stats statistiscs : statsList) {//這個(gè)是對(duì)于多個(gè)SolrIndexSearcher之間的統(tǒng)計(jì),不過(guò)現(xiàn)在我做測(cè)試發(fā)現(xiàn)并沒(méi)有開(kāi)啟,也就是統(tǒng)計(jì)的還是一個(gè)SolrIndexSearcher生存期間的緩存使用情況,
clookups += statistiscs.getCumulativeLookups();
chits += statistiscs.getCumulativeHits();
cinserts += statistiscs.getCumulativePuts();
cevictions += statistiscs.getCumulativeEvictions();
}
lst.add(“l(fā)ookups”, lookups);//返回的結(jié)果包括這些:
lst.add(“hits”, hits);
lst.add(“hitratio”, calcHitRatio(lookups, hits));
lst.add(“inserts”, inserts);
lst.add(“evictions”, evictions);
lst.add(“size”, size);
lst.add(“warmupTime”, warmupTime);
lst.add(“cumulative_lookups”, clookups);
lst.add(“cumulative_hits”, chits);
lst.add(“cumulative_hitratio”, calcHitRatio(clookups, chits));
lst.add(“cumulative_inserts”, cinserts);
lst.add(“cumulative_evictions”, cevictions);
if (showItems != 0) {//showItem的意思是將多少個(gè)緩存的key展示出來(lái),展示最近搜索的,
Map items = cache.getLatestAccessedItems( showItems == -1 ? Integer.MAX_VALUE : showItems );
for (Map.Entry e : (Set 《Map.Entry》)items.entrySet()) {
Object k = e.getKey();
Object v = e.getValue();
String ks = “item_” + k;
String vs = v.toString();
lst.add(ks,vs);
}
}
return lst;
}
評(píng)論