§ 1。配置Lucene,對ccer數據建立索引和查詢(xún)系統
中文分詞模塊(IKAnalyzer可選)
§ 2。閱讀代碼,分析Lucene的ranking算法。寫(xiě)一個(gè)簡(jiǎn)短的報告文檔。
§ 3。改進(jìn)ranking算法,并進(jìn)行評估,給出一個(gè)實(shí)驗報告。
算法改進(jìn)可用方法:PageRank Combination, LSI, Language Model, or…
評估指標可用:P@10, MAP, F1, or …
評估方法可用:human judgment or auto compare with google result or …
1. 使用IKAnalyzer對ccer下的18652左右的網(wǎng)頁(yè)進(jìn)行了索引建立和查詢(xún)系統的建立,索引建立的過(guò)程大概持續了10分鐘,CPU使用率持續100%。下面是索引建立之后的文件。
Index文件 (調用了optimize之后的結果)
實(shí)現代碼如下。(附件中)
(我們做的是將目標的URL和所得的分數顯示出來(lái))
查詢(xún)結果如下:
(1)搜“北京大學(xué)”
ReadNews.asp?NewsID=1487 0.14996947
readview.asp?reviewID=2296&NewsID=24960.14321162
ReadNews.asp?NewsID=83950.14157297
ReadNews.asp?NewsID=4173 0.14049698
ReadNews.asp?NewsID=1890 0.14018208
ReadNews.asp?NewsID=3450 0.13792434
readview.asp?reviewID=2958&NewsID=30200.13510498
ReadNews.asp?NewsID=6009 0.13157436
ReadNews.asp?NewsID=2808 0.13154271
ReadNews.asp?NewsID=1587 0.12664454
18292 pages(s) found (in 63 milliseconds)
我看了下網(wǎng)頁(yè)中的內容,搜索結果中,第一個(gè)網(wǎng)頁(yè)有39處匹配,文檔內容也較長(cháng)。第二個(gè)網(wǎng)頁(yè)有3處匹配,文檔內容很短。第三個(gè)網(wǎng)頁(yè)有27處匹配,文檔內容較長(cháng)。。。
(2)第二次搜索是針對第一次搜索結果中,排在第三位的網(wǎng)頁(yè)中的內容。網(wǎng)頁(yè)中有一個(gè)獲得全國三好學(xué)生的學(xué)生名字,叫“曾垚”。試下看看結果。
ReadNews.asp?NewsID=8395 0.73862696
ReadNews.asp?NewsID=8448 0.10303292
ReadNews.asp?NewsID=10894 0.10303292
news.asp?alllistpage=91 0.09587039
ReadNews.asp?NewsID=10557 0.09587039
ReadNews.asp?NewsID=6889 0.09587039
6 pages(s) found (in 31 milliseconds)
果然,第一個(gè)匹配的網(wǎng)頁(yè)是第一次搜索的第三個(gè)網(wǎng)頁(yè),結果還不錯。
2.通過(guò)閱讀相關(guān)文檔和源代碼,Lucene的Ranking算法中,包括score的計算和相似度分析。
Lucene 將信息檢索中的Boolean model (BM)和Vector Space Model(VSM)聯(lián)合起來(lái),實(shí)現了自己的評分機制。VSM模型如下:
計算某個(gè)查詢(xún)q的文檔d得分如下(摘自API文檔注釋):
其中每個(gè)因子的分析如下:
1) 在Lucene的實(shí)現中,使用了
2) 反映有多少個(gè)文檔包含了該term,文檔數越多,該因子的值越小,反之越大。計算idf的常用方法為
3) 查詢(xún)時(shí)期t的加權,或者由t.setBoost(int boost)來(lái)指定
4) 壓縮幾個(gè)索引期間的加權和長(cháng)度因子。計算公式如下:
其中的因子解釋如下:
Document boost:
文檔加權。在索引創(chuàng )建過(guò)程中寫(xiě)入了索引中。用 doc.setBoost()
Field boost:
字段加權,在索引創(chuàng )建過(guò)程中寫(xiě)入了索引中。 field.setBoost()
lengthNorm(field):
由字段(Field)內的 Token 的個(gè)數來(lái)計算此值,字段越短,評分越高,在做索引的時(shí)候由Similarity.lengthNorm 計算。
5) 評分因子,是基于文檔中出現查詢(xún)項的個(gè)數。越多的查詢(xún)項在一個(gè)文檔中,說(shuō)明些文檔的匹配程序越高。
6) 查詢(xún)的標準查詢(xún),使不同查詢(xún)之間可以比較。此因子不影響文檔的排序,因為所有有文檔都會(huì )使用此因子。這個(gè)因子是在查詢(xún)的時(shí)候計算的。
而sumOfSquareWeights的計算由下面來(lái)得到:
(注:以上部分摘自L(fǎng)ucene的API文檔的英文部分,自己進(jìn)行了理解和翻譯)
- 在Lucene中計算的具體過(guò)程分析如下:
在Lucene的Ranking計算過(guò)程中,包括了Query、Weight、Score、Similarity,Collector幾個(gè)不同的類(lèi)。文檔匹配階段主要調用Searcher對象的search方法,在search方法內部,通過(guò)直接或間接調用,search(Weightweight, Filter filter, Collectorcollector)方法。通過(guò)閱讀源代碼,使用search的時(shí)候都將得到一個(gè)Weight對象(第一個(gè)的search方法顯示調用了Query的createWeight方法來(lái)創(chuàng )建一個(gè)Weight對象),Weight對象會(huì )創(chuàng )建一個(gè)Scorer對象,Scorer對象來(lái)進(jìn)行score函數的調用并將結果保存在Collector對象中。如下:
。
public void search(Query query,Collector results)
throwsIOException {
search(createWeight(query), null, results);
}
@Override
public voidsearch(Weight weight, Filter filter, Collectorcollector)
throws IOException {
if(filter == null) {//沒(méi)有使用Filter對象的時(shí)候
for (int i = 0; i < subReaders.length;i++) { // 遍歷每個(gè)subReader,但在indexSearcher中,只有一個(gè)reader
collector.setNextReader(subReaders[i], docStarts[i]);
Scorer scorer = weight.scorer(subReaders[i],!collector.acceptsDocsOutOfOrder(),true);//創(chuàng )建了一個(gè)scorer對象
if (scorer != null) {
scorer.score(collector);//將結果保存在collector中,以便后邊使用
}
}
}else {
for (int i = 0; i < subReaders.length;i++) { // search each subreader
collector.setNextReader(subReaders[i], docStarts[i]);
searchWithFilter(subReaders[i], weight, filter,collector);
}
}
}
public Weightweight(Searcher searcher) throws IOException {
Query query= searcher.rewrite(this);
Weightweight = query.createWeight(searcher);
floatsum = weight.sumOfSquaredWeights();
floatnorm = getSimilarity(searcher).queryNorm(sum);
if(Float.isInfinite(norm) || Float.isNaN(norm))
norm = 1.0f;
weight.normalize(norm);//歸一化
return weight;
}
在源代碼中可以看出(沒(méi)有列出),在IndexReader中的subReaders數組中存放的只有原reader,沒(méi)有其他的reader,那么docStarts數組中也是一個(gè)只包含一個(gè)0的長(cháng)度為1的數組。構造Weight對象,通過(guò)調用scorer函數來(lái)構造Score對象,得到所有符合要求的文檔序列。
IDF的計算:(在DefaultSimilarity類(lèi)中)
public floatidf(int docFreq, int numDocs) {
return(float)(Math.log(numDocs/(double)(docFreq+1))+ 1.0);
}
TF的計算:(在DefaultSimilarity中)
publicfloat tf(float freq) {
return (float)Math.sqrt(freq);
}
得到Boost:(在Query類(lèi)中。雖然在Fieldable接口和Document類(lèi)中也有setBoost方法,但是還是建議在Query中調用,因為在Fieldable和Document中定義boost的話(huà),會(huì )一同寫(xiě)到index中,想改變boost會(huì )變得困難。如果確實(shí)想提高一個(gè)文檔或文檔中某個(gè)Field的分值,可以同index一起寫(xiě)到索引文件中)
public float getBoost() { return boost;}//Query類(lèi)中的方法
3. Lucene的Ranking算法的結果主要有Score和Similarity來(lái)進(jìn)行計算,所以要改進(jìn)Ranking算法,要從這兩個(gè)方面入手。
思路:
1) 網(wǎng)頁(yè)的重要性
對網(wǎng)頁(yè)的鏈接分析得到。網(wǎng)頁(yè)的鏈接分析主要根據外部鏈接網(wǎng)頁(yè)的數量和鏈接網(wǎng)頁(yè)的質(zhì)量,網(wǎng)頁(yè)內容的主題相關(guān)性等內容,確定網(wǎng)頁(yè)重要性。來(lái)改變Score的計算結果。
2) 關(guān)鍵詞匹配程度:
根據關(guān)鍵字匹配的算法,對基本的檢索理論進(jìn)行改進(jìn),針對不同位置、不同格式、不同形式的關(guān)鍵詞,進(jìn)行綜合計算,最終得到每個(gè)文檔與檢索相關(guān)的匹配程度。