http://www.cnblogs.com/ibook360/archive/2011/10/19/2217638.htmlhtml
Lucene3.0之結果排序(原理篇)
java
傳統上,人們將信息檢索系統返回結果的排序稱爲"相關排序" (relevance ranking) ,隱含其中各條目的順序反映結果和查詢的相關程度。 apache
一、 基本排序原理函數
① 向量空間模型搜索引擎
Gerald Salton 等在 30 多年前提出的"向量空間模型" (Vector Space Model,VSM)[Salton and Lesk,1968, Salton,1971]。該模型的基礎是以下假設:文檔d和查詢q的相關性能夠由它們包含的共有詞彙狀況來刻畫。 spa
經典的TF*IDF詞項權重的計算公式: 設計
給定某種權重的定量設計,求文檔和查詢的相關性就變成了求 d 和 q 向量的 3d
某種距離,最經常使用的是餘弦(cos)距離 htm
② 連接分析PageRank原理對象
連接分析技術主要基於兩個假設:1)一個網頁被屢次引用,則它多是很重要的,若是被重要的網頁引用,說明自身也是重要的,網頁的重要性在網頁之間能夠傳遞。
2)隨機衝浪模型:認爲假定用戶一開始隨機地訪問網頁集合中的一個網頁,然和跟隨網頁的連接向前瀏覽網頁,不會退瀏覽,那麼瀏覽下一個網頁的機率是被瀏覽網頁的量化的重要程度值。
按照以上的用戶行爲模型,每一個網頁可能被訪問到的次數越多就越重要,這樣的"可能被訪問的次數"也就定義爲網頁的權值,PageRank值。如何計算這個權值呢?PageRank採用如下公式進行計算:
其中wj表明第j個網頁的權值;lij只取0、1值,表明從網頁i到網頁j是否存在連接;ni表明網頁i有多少個連向其它網頁的連接;d表明"隨機衝浪"中沿着連接訪問網頁的平均次數。選擇合適的初始數值,遞歸的使用上述公式,便可獲得理想的網頁權值。
二、 Lucene排序計算公式
Lucene的排序公式以下:
1),協調因子,表示文檔(d)中Term(t)出現的百分比,也就是計算查詢條件(q)中不一樣Term(t),以及在文檔中出現的數量之和,二者的數量之比。一般在文檔中出現查詢Term種類越多,分值越高。
2),調節因子,不影響索引排序狀況,只在檢索時使用,主要是用來讓排序結果在不一樣的查詢條件之間能夠比較。這個條件是在搜索時候計算。數值是根據每個查詢項權重的平方和計算獲得。計算公式以下:
3) ,文檔頻率,表示查詢詞中,每一個Term在對應的結果文檔中(d)中出現的次數。查詢詞出現的次數越多,表示出現頻率越高,文檔的檢索得分就越高。爲了不得到更大的相關性函數,實際中,使用次數的平方跟做爲文檔頻率tf的值,避免數值過分放大。
4) ,逆文檔頻率,檢索匹配文檔數量的反向函數。按照信息理論,文檔出現的次數越少,每一篇文檔的信息量就會越大。因此匹配的文檔數越少,得分就越高。而索引庫中文檔總數越多,找到一篇目標文檔難度越大,相應的信息量也會比較大。
5) ,長度因子,每一個索引詞彙在域中的整體長度決定的,這個參數在索引創建時肯定。數值根據文檔中實際具備的索引項個數肯定。檢索詞長度在文檔總長度中佔的比例越大,長度因子的數值也越大。
Lucene3.0之結果排序(操做篇)
一、 Lucene相關排序流程
二、 Lucene相關類
① Query類:一個抽象類,Lucene檢索結果最終評分的總控制中心。其它評分有關的類和對象都是由Query類來管理和生產。
② Weight類接口:定義Query權重計算的一個實現接口,能夠被重用。Weight類能夠用來生成Scorer類,也能夠解析評分的詳細信息,另外還定義了獲取Query權值的方法。
③ Scorer類:Lucene評分機制的核心類。類的定義是抽象類,提供的一些抽象基本的計分功能方法提供全部的評分類實現,同時還定義了評分的詳細解析方法,Scorer類內部有一個Similarity對象,用來指明計算公式。
④ Scorer類:Lucene類似度計算的核心抽象類。Similarity類主要處理評分計算,系統缺省使用類DefaultSimilarity類對象
三、 排序控制
使用Sort對象定製排序,經過改變文檔Boost值來改變排序結果以及使用自定義的Similarity方法更改排序
四、 文檔Boost加權排序
① Boost是指索引創建過程當中,給整篇文檔或者文檔的某一特定域設定的權值因子,在檢索時,優先返回分數高的。
Document和Field兩重Boosting參數。經過Document對象的setBoost()方法和Field對象的setBoost()方法。不一樣在於前者對文檔中每個域都修改了參數,然後者只針對指定域進行修改。
文檔加權=Document-boosting*Field-boosting,默認狀況下爲1,通常不作修改。
② Sort對象檢索排序
Sort使用時經過實例化對象做爲參數,經過Searcher類的search接口來實現。Sort支持的排序功能以文檔當中的域爲單位,經過這種方法,能夠實現一個或者多個不一樣域的多形式的值排序。
實際使用排序對象Sort進行排序。主要有兩種模式,一種是以字符串表示文檔域的名稱做爲參數指定域排序,一種是直接以排序域的包裝域的包裝類做爲參數進行排序。
Sort對象使用比較簡單,只須要在對文檔索引進行檢索時,在檢索器的Search方法中帶Sort對象做爲參數便可。
1) Sort對象相關性排序
按照相關性排序時最基本的結果排序方法,使用Sort對象無參數構造函數完成的排序效果至關於Lucene默認的按相關性降序排序。
2) Sort對象文檔編號排序
某些應用場合須要對全部符合匹配度的結果,按照文檔內部編號排序輸出。使用Sort對象的靜態實例Sort.INDEXORDER來實現
3) Sort對象獨立域排序
在檢索過程當中,把檢索結果按照某一個特定域排 序,很是重要。在使用搜索引擎過程當中,有時會選擇使用時間排序,而在搜索引擎庫中,檢索詞徹底是另一個域的內容,與時間沒有任何關係。這種應用中,檢索 關鍵詞的匹配仍然是首要因素,匹配過低或者不匹配的文檔直接沒必要處理,而匹配的文檔則需進一步排序輸出。
指定的排序域並無進行特別限制,能夠是檢索詞的關聯域,也能夠是文檔中的任意其它域。
4) Sort對象聯合域排序
多個文檔域聯合排序時,須要注意文檔域的添加次序。排序的結果先按照第一個域排序,而後第二個域做爲次要關鍵字排序。開發時,須要根據本身的須要選擇合適的次序。
5) Sort對象逆向排序
Sort(field,true)或者Sort(field,false)實現升降序排序。
Lucene3.0之結果排序(示例篇)
這個例子是根據《開發本身的搜索引擎:Lucene2.0+Heritrix》中的例子改的,因爲原書中是使用Lucene2.0,因此代碼有部分改動。
package sortApp;
import java.io.File;
import org.apache.lucene.analysis.standard.StandardAnalyzer;
import org.apache.lucene.document.Document;
import org.apache.lucene.document.Field;
import org.apache.lucene.index.IndexWriter;
import org.apache.lucene.index.Term;
import org.apache.lucene.index.IndexWriter.MaxFieldLength;
import org.apache.lucene.search.IndexSearcher;
import org.apache.lucene.search.ScoreDoc;
import org.apache.lucene.search.Sort;
import org.apache.lucene.search.TermQuery;
import org.apache.lucene.store.Directory;
import org.apache.lucene.store.FSDirectory;
import org.apache.lucene.util.Version;
public class SortTest {
public static void makeItem(IndexWriter writer, String bookNumber,
String bookName, String publishDate) throws Exception {
writer.setUseCompoundFile(false);
Document doc = new Document();
Field f1 = new Field("bookNumber", bookNumber, Field.Store.YES,
Field.Index.NOT_ANALYZED);
Field f2 = new Field("bookName", bookName, Field.Store.YES,
Field.Index.ANALYZED);
Field f3 = new Field("publishDate", publishDate, Field.Store.YES,
Field.Index.NOT_ANALYZED);
doc.add(f1);
doc.add(f2);
doc.add(f3);
writer.addDocument(doc);
}
public static void main(String[] args) {
String Index_Store_Path = "D:/index/1";
File file = new File(Index_Store_Path);
try {
Directory Index = FSDirectory.open(file);
IndexWriter writer = new IndexWriter(Index, new StandardAnalyzer(Version.LUCENE_CURRENT), true,
MaxFieldLength.LIMITED);
writer.setUseCompoundFile(false);
Document doc1 = new Document();
Field f11 = new Field("bookNumber", "0000001", Field.Store.YES, Field.Index.NOT_ANALYZED);
Field f12 = new Field("bookName", "鋼鐵是怎樣煉成的", Field.Store.YES, Field.Index.ANALYZED);
Field f13 = new Field("publishDate", "1970-01-01", Field.Store.YES, Field.Index.NOT_ANALYZED);
doc1.add(f11);
doc1.add(f12);
doc1.add(f13);
Document doc2 = new Document();
Field f21 = new Field("bookNumber", "0000002", Field.Store.YES, Field.Index.NOT_ANALYZED);
Field f22 = new Field("bookName", "鋼鐵戰士", Field.Store.YES, Field.Index.ANALYZED);
Field f23 = new Field("publishDate", "1970-01-01", Field.Store.YES, Field.Index.NOT_ANALYZED);
doc2.add(f21);
doc2.add(f22);
doc2.add(f23);
Document doc3 = new Document();
Field f31 = new Field("bookNumber", "0000003", Field.Store.YES, Field.Index.NOT_ANALYZED);
Field f32 = new Field("bookName", "籬笆女人和狗", Field.Store.YES, Field.Index.ANALYZED);
Field f33 = new Field("publishDate", "1970-01-01", Field.Store.YES, Field.Index.NOT_ANALYZED);
doc3.add(f31);
doc3.add(f32);
doc3.add(f33);
Document doc4 = new Document();
Field f41 = new Field("bookNumber", "0000004", Field.Store.YES, Field.Index.NOT_ANALYZED);
Field f42 = new Field("bookName", "女人是水作的", Field.Store.YES, Field.Index.ANALYZED);
Field f43 = new Field("publishDate", "1970-01-01", Field.Store.YES, Field.Index.NOT_ANALYZED);
doc4.add(f41);
doc4.add(f42);
doc4.add(f43);
Document doc5 = new Document();
Field f51 = new Field("bookNumber", "0000005", Field.Store.YES, Field.Index.NOT_ANALYZED);
Field f52 = new Field("bookName", "英雄兒女", Field.Store.YES, Field.Index.ANALYZED);
Field f53 = new Field("publishDate", "1970-01-01", Field.Store.YES, Field.Index.NOT_ANALYZED);
doc5.add(f51);
doc5.add(f52);
doc5.add(f53);
Document doc6 = new Document();
Field f61 = new Field("bookNumber", "0000006", Field.Store.YES, Field.Index.NOT_ANALYZED);
Field f62 = new Field("bookName", "白毛女", Field.Store.YES, Field.Index.ANALYZED);
Field f63 = new Field("publishDate", "1970-01-01", Field.Store.YES, Field.Index.NOT_ANALYZED);
doc6.add(f61);
doc6.add(f62);
doc6.add(f63);
Document doc7 = new Document();
Field f71 = new Field("bookNumber", "0000007", Field.Store.YES, Field.Index.NOT_ANALYZED);
Field f72 = new Field("bookName", "個人兄弟和女兒", Field.Store.YES, Field.Index.ANALYZED);
Field f73 = new Field("publishDate", "1970-01-01", Field.Store.YES, Field.Index.NOT_ANALYZED);
doc7.add(f71);
doc7.add(f72);
doc7.add(f73);
writer.addDocument(doc1);
writer.addDocument(doc2);
writer.addDocument(doc3);
writer.addDocument(doc4);
writer.addDocument(doc5);
writer.addDocument(doc6);
writer.addDocument(doc7);
writer.optimize();
writer.close();
IndexSearcher searcher = new IndexSearcher(Index);
TermQuery q = new TermQuery(new Term("bookName", "女"));
ScoreDoc[] hits = searcher.search(q, null, 1000, Sort.RELEVANCE).scoreDocs;
for (int i = 0; i < hits.length; i++) {
Document hitDoc = searcher.doc(hits[i].doc);
System.out.print("書名:");
System.out.println(hitDoc.get("bookName"));
System.out.print("得分:");
System.out.println(hits[i].score);
System.out.print("內部ID :");
System.out.println(hits[i].doc);
System.out.print("書號:");
System.out.println(hitDoc.get("bookNumber"));
System.out.print("發行日期:");
System.out.println(hitDoc.get("publishDate"));
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
運行結果:
Sort屬性設爲RELEVANCE:
Sort屬性設爲INDEXORDE:
去除Sort參數後: