Lucene打分规则与Similarity模块详解
https://my.oschina.net/BreathL/blog/51498
搜索排序結果的控制
? ????Lucnen作為搜索引擎中,應用最為廣泛和成功的開源框架,它對搜索結果的排序,有一套十分完整的機制來控制;但我們控制搜索結果排序的目的永遠只有一個,那就是信息過濾,讓用戶快速,準確的找到其想要的結果,豐富用戶體驗。
以前看過一個牛人的博客,總結了4個地方,可對Lucene檢索結果的排序進行控制,現在已經記不住。我自己簡單整理了下面幾個,若有疏漏,歡迎補充:
1.????通過Lucene自有的查詢表達式:Lucene提供相當豐富的表達式解析,要細講就多了去了;這里只強調下,我在項目中用的比較多的是通過對指定域的加權,來影響檢索結果(例如:field1:(XXX)^10 or field2:(XXX)^5;其中XXX是用戶提交的檢索)
2.????權重的控制:這是在建索引的時候就寫入索引的,查詢時只是讀取出來,用乘的方式來對一些檢索結果加分。據我自己看Lucene代碼,Similarity中也能在建索引時,對權重的寫入進行控制;后面會細講。
3.????Controller?模塊:Lucene的排序流程控制模塊,里面提供的一些接口能讓你對打分后的搜索結果進行一些篩選和調整。
?4.????Similarity?模塊:Lucene的搜索結果打分控制模塊,也是這里要詳細分析的模塊。他能讓你對一個檢索結果的打分進行優化,或面目全非,哈哈。
?
?
Lucene的打分公式
?
????? ??要理解Similarity模塊對打分結果控制,首先要了解Lucene自己評分原理:相似度評分公式;次公式是目前公認的用戶體驗較好的一個,原理是根據余弦定理,我在以前的博文中有介紹過。下面是在摘自?《Lucene實戰》(第二版)的公式表達式:
?
其中q?為查詢語句,t?是q?分詞后的每一項,?d為去匹配的文檔。
??????接下來對公式中的每一個函數,進行詳解,他們都能在?Similarity?模塊中進行控制。
?
?
?
Lucene打分流程
?
????? ??首先,我簡單說明下,Lucene對一次查詢是如何封裝;這涉及到對打分公式是如何調用的,如此一來更能全面的了解打分流程:
?????????第一步的處理肯定是分詞,查詢語句?=> term_1, term_2 …? term_n(n∈[1,∞]),緊接著是將這些term?封裝成Query對象,總的Query對象是BooleanQuery,它里面包含和分詞數相同TermQuery,和分詞后的詞項一一對應;這是對一個域的查詢,若你多個域聯合查詢,那就會有多個這樣的BooleanQuery,被一個更大的BooleanQuery包裹著。
?????????而打分公式,貫穿所有Query,其中一部分在TermQuery中計算,一部分在BooleanQuery計算,最后按此計算出的得分進行排序,就得到了我們的搜索結果。
?????????下面是我通過explain(Query?query, int doc)?導出的打分解釋:
?
????????對照Lucene的打分解釋,我們一層一層往里撥(上述每個縮進為一層),每一個函數都能在Similarity中進行控制。
1.??????首先第一層:3.3936599 = (MATCH) product of:,是此條記錄的總得分。
2.??????第二層:8.48414992 = (MATCH) sum of:?它對應一個BooleanQuery,它把它包含的TermQuery的得分累加起來,由于TermQuery總共有5個,此條結果中只匹配了2個,所以最后一行將得分乘以了0.4得到最后的打分,coord()在Similarity中的默認實現如下:
?
/** Implemented as <code>overlap / maxOverlap</code>. */?
你也可以繼承Similarity對此方法重寫。
3.??????第三層:(MATCH) weight(field:XXX in m), product of:?有2個,它們分別是“三國”、“無雙”對應的詞項查詢TermQuery的得分。
????????再往里,就是TermQuery的打分規則了,里面的函數已經和公式有所對應了,下面就詳細介紹TermQuery中每一項計算的作用。
Similarity?函數詳解
? ??TermQuery中有4個函數,都是Similarity里可以控制的函數,他們分別是queryNorm、tf、idf、fieldNorm;其中queryNorm對于某一次搜索中結果的排序沒有影響,在一次搜索中queryNorm的值是固定的。這里就不介紹了
tf(t in q)
?????????此函數表示詞項T?在該文檔中的該字段里?出現的頻率;對應到上圖的例子中:既是分詞后的詞項(三國?或?無雙)在此條記錄中Name字段里出現的頻率。當然出現的次數越多,它返回的值越大,也正好反映了此文檔的重要性。下面是DefaultSimilarity?中的默認實現的默認實現。? ??
?
/** Implemented as <code>sqrt(freq)</code>. */@Overridepublic float tf(float freq) { return (float)Math.sqrt(freq); }?
?
?????????默認實現是開平方。同樣你可以重寫此函數。
?????????它實際對結果排序的影響,表現和它的意義一樣,一個搜索結果包含的搜索關鍵詞越多,得分越高。
idf(t)
?????????此函數出現了兩次,也剛好對應公式中的?idf(t)^2;
?????????這個函數被稱作倒頻率,表示詞項T?在所有文檔中出現的頻率。若它在所有文檔中出現的次數越多,表明這個詞項T?越不重要;以下是DefaultSimilarity的默認實現。
?
/** Implemented as <code>log(numDocs/(docFreq+1)) + 1</code>. */@Overridepublic float idf(int docFreq, int numDocs) { return (float)(Math.log(numDocs/(double)(docFreq+1)) + 1.0); }?
?????????此函數實際對結果排序的影響,在于當一次搜索包含多個詞項時,文檔A和B分別包含了其中一個詞項;比如A包含“三國”,B包含“無雙”;那么“三國”和“無雙”的倒頻率就會影響,讓A、B的得分產生差異了。若詞項只有一個,那本次搜索idf(t)?實際對結果排序不會產生影響。
?
fieldNorm (t)
?????????它的值對應著公式中?boost(t.field in d)×lengthNorm(t.field in d)?的值。其中boost(t.field in d)的值,在創建索引時就被記錄下來,而lengthNorm(t.field in d)得值,會在查詢過程中計算;它表示此條搜索結果中,給定字段中包含詞項的總數;若值越大,得分越低;你可以這么理解;若A文檔有包含了1000個詞項,關鍵詞出現的頻率為10;而B文檔包20個詞項,相同關鍵詞出現的頻率為8;很明顯B文檔的打分應該要高一些;由此函數可以起到這樣的效果。以下是Similarity?的默認實現,函數名在3.0以后變了,原來就叫lengthNorm
?
/** Decodes a normalization factor stored in an index.* <p>* <b>WARNING: If you override this method, you should change the default* Similarity to your implementation with {@link Similarity#setDefault(Similarity)}. * Otherwise, your method may not always be called, especially if you omit norms * for some fields.</b>* @see #encodeNormValue(float)*/public float decodeNormValue(byte b) { return NORM_TABLE[b & 0xFF]; // & 0xFF maps negative bytes to positive above 127 }?
? ? ? 至此Lucene打分流程和Similarity模塊的函數已經將的差不多了。可以通過這些函數讓你的搜索展示出完全不一樣的效果,這也需要根據不同的業務慢慢調試,才能得出最優化的搜索結果?
轉載于:https://www.cnblogs.com/davidwang456/articles/10401224.html
總結
以上是生活随笔為你收集整理的Lucene打分规则与Similarity模块详解的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 你的响应阻塞了没有?--Spring-W
- 下一篇: API Gateways – An Ev