Lucene打分公式的推導

lucene 介紹

lucene是一個高效的,基於Java的全文檢索庫,利用lucene能夠很方便加入到現有應用中來提供全文檢索的功能。好比分佈式搜索引擎Elastic Search底層的搜索就是使用lucene。(全文檢索是從大量的現有的文檔中,搜索出與查詢語句最相關的文檔集的過程)java

爲了更高效的完成全文檢索的過程,lucene使用倒排索引來完成查詢詞到文檔查找。lucene全文檢索的過程主要由建立索引和搜索索引,本文主要介紹文檔相關性排序部分。mysql

lucene中相關概念:sql

  • document:lucene存儲的基本單位,相似於mysql數據庫中一條記錄
  • field:document中一個字段,相似於mysql數據庫表中一個字段

note:本文分析的lucene版本爲5.1.0數據庫

倒排索引模型網絡

左邊一列是按照必定順序排列的通過分詞處理後的Term,稱爲字典;每一個詞都指向的包含該詞的文檔組成鏈表稱爲倒排表。分佈式

lucene處理流程搜索引擎

建立索引的過程:spa

  • 準備待索引的原文檔,數據來源多是文件、數據庫或網絡
  • 對文檔的內容進行分詞組件處理,造成一系列的Term
  • 索引組件對文檔和Term處理,造成字典和倒排表

搜索索引的過程:3d

  • 對查詢語句進行分詞處理,造成一系列Term
  • 根據倒排索引表查找出包含Term的文檔,並進行合併造成符合結果的文檔集
  • 比對查詢語句與各個文檔相關性得分,並按照得分高低返回

評分公式推導

空間向量模型code

lucene的評分計算模型是基於VSM,即空間向量模型,但實現上稍有不一樣。
空間向量模型的邏輯就是將每一個文檔看作是由N個Term組成的向量,文檔間相關性就是兩個向量的在N維空間內的夾角大小,因爲兩個向量的之間的夾角越小,相關性就越大,因此就能夠將夾角的餘弦值做爲相關性的得分,夾角越小,餘弦值越大,相關性越大。

VSM(空間向量模型) 計算公式:

好比索引中的文檔
Document Vector = {Weight1, Weight2, ..., Weight N},查詢語句也能夠看作是一個文檔,查詢文檔:Query Vector = {Weight1, Weight2, ..., Weight N},Weight是某個Term的權重,N是全部文檔包括查詢文檔在內的全部Term總數,若是文檔不包含某個Term,則文檔向量中Term的Weight爲0。

Term的權重計算

影響一個Term在文檔中權重大小的因素主要有兩個:

  • Term Frequency(tf):即該Term在該文檔中出現的次數,tf越大說明越重要;
  • Document Frequency(df):即有多少個文檔包含了該Term,df越小說明越重要;

計算公式:

以上是Term weight計算的典型實現,Lucene實現於此稍有不一樣,使用的是tf(t in d ) * idf(t)。

lucene公式推導

咱們首先計算餘弦公式的分子部分,也即兩個向量的點積:

在這裏有三點須要指出:

  • 因爲是點積,則此處的 t1, t2, ..., tn 只有查詢語句和文檔的並集有非零值,只在查詢語句出現的或只在文檔中出現的 Term 的項的值爲零。
  • 在查詢的時候,不多有人會在查詢語句中輸入一樣的詞,於是能夠假設 tf(t, q)都=1
  • idf 是指 Term 在多少篇文檔中出現過,其中也包括查詢語句這篇小文檔,於是 idf(t, q)和 idf(t, d)實際上是同樣的,是索引中的文檔總數加一,當索引中的文檔總數足夠大的時候,查詢語句這篇小文檔能夠忽略,於是能夠假設 idf(t, q) = idf(t, d) = idf(t)

下面推導查詢語句的長度
由上面的討論,查詢語句中 tf 都爲 1,idf 都忽略查詢語句這篇小文檔,獲得以下公式:

接下來推導文檔的長度
爲何在打分過程當中,須要除以文檔的長度呢? 由於在索引中,不一樣的文檔長度不同,很顯然,對於任意一個 term,在長的文檔中的 tf 要大的多,於是分數也越高,這樣對小的文檔不公平,舉一個極端的例子,在一篇 1000 萬 個詞的鴻篇鉅著中,「lucene」 這個詞出現了 11 次,而在一篇 12 個詞的短小文檔中,「lucene」 這個詞出現了 10 次,若是不考慮長度在內,固然鴻篇鉅著應該分數更高,然而顯然這篇小文檔纔是真正關注「lucene」 的。然而若是按照標準的餘弦計算公式,徹底消除文檔長度的影響,則又對長文檔不公平(畢竟它是包含更多的信息),偏向於首先返回短小的文檔的,這樣在實際應用中使得搜索結果 很難看。

在默認情況下,Lucene 採用 DefaultSimilarity,認爲在計算文檔的向量長度的時候,每一個 Term 的權重就再也不考慮在內了,而是所有爲一。

再加上各類 boost 和 coord,則可得出 Lucene 的計算公式

lucene計算公式

coord(q,d):得分因子,score factor,一個文檔中包含越多的查詢Term詞,則該文檔的得分越高,對應lucene類TFIDFSimilarity.coord(int overlap, int maxOverlap)

queryNorm(q):歸一化因子,normalizing factor,使得不一樣查詢間的得分具備可比性,但並不會影響文檔的排序,對應lucene類TFIDFSimilarity.queryNorm(float sumOfSquaredWeights)

tf(t in d):Term在文檔d中出現的次數,對應lucene類TFIDFSimilarity.tf(float freq)

idf(t):Term的逆文檔頻率,即一個Term在全部文檔中出現的次數越多,重要性越小,對應lucene類TFIDFSimilarity.idf(long docFreq, long numDocs)

norm(t,d):封裝了文檔字段field的權重和field內容長度因子,在index時計算,對應lucene類 TFIDFSimilarity.computeNorm(FieldInvertState state)

lengthNorm:field內容長度因子,field字段內容長度越短,則值越大,對應lucene類TFIDFSimilarity.lengthNorm(FieldInvertState state);

q.getBoost():查詢的權重(默認值爲1.0)
t.getBoost():子查詢的權重(默認值爲1.0)
f.getBoost():filed字段的權重(認值爲1.0)

設置Query權重

BooleanQuery parentQuery=new BooleanQuery();
parentQuery.setBoost(1.0f);

TermQuery termQuery=new TermQuery(new Term("search"));
termQuery.setBoost(2.0f);
parentQuery.add(termQuery,BooleanClause.Occur.SHOULD);

termQuery=new TermQuery(new Term("掘金"));
termQuery.setBoost(2.0f);
parentQuery.add(termQuery,BooleanClause.Occur.SHOULD);

reader=DirectoryReader.open(index_directory);
IndexSearcher searcher=new IndexSearcher(reader);

TopScoreDocCollector collector=TopScoreDocCollector.create(5);
searcher.search(parentQuery,collector);
ScoreDoc[]hits=collector.topDocs().scoreDocs;複製代碼

設置Field權重

Document document = new Document();
TextField questionField = new TextField(FieldConstants.QUESTION, question, Field.Store.YES);
questionField.setBoost(2.0f);
TextField answerField = new TextField(FieldConstants.ANSWER, question, Field.Store.YES);
answerField.setBoost(2.0f);

document.add(questionField);
document.add(answerField);
documents.add(document);複製代碼

note:從lucene4.0以後就不在支持設置document的boost,應該使用filed

相關文章
相關標籤/搜索