1. 程式人生 > >【Elasticsearch】打分策略詳解與explain手把手計算

【Elasticsearch】打分策略詳解與explain手把手計算

一、目的

一個搜尋引擎使用的時候必定需要排序這個模組,一般情況下在不選擇按照某一欄位排序的情況下,都是按照打分的高低進行一個預設排序的,所以如果正式使用的話,必須對預設排序的打分策略有一個詳細的瞭解才可以,否則被問起來為什麼這個在前面,那個在後面不好辦,因此對Elasticsearch的打分策略詳細的看了下,雖然說還不是瞭解的很全部,但是大部分都看的差不多了,結合理論以及搜尋的結果,做一個簡單的介紹

二、Elasticsearch的打分公式

Elasticsearch的預設打分公式是lucene的打分公式,主要分為兩部分的計算,一部分是計算query部分的得分,另一部分是計算field部分的得分,下面給出ES官網給出的打分公式:

score(q,d)  =  
            queryNorm(q)  
          · coord(q,d)    
          · ∑ (           
                tf(t in d)   
              · idf(t)²      
              · t.getBoost() 
              · norm(t,d)    
            ) (t in q)    
在此給每一個部分做一個解釋

queryNorm(q):

對查詢進行一個歸一化,不影響排序,因為對於同一個查詢這個值是相同的,但是對term於ES來說,必須在分片是1的時候才不影響排序,否則的話,還是會有一些細小的區別,有幾個分片就會有幾個不同的queryNorm值

queryNorm(q)=1 / √sumOfSquaredWeights 

上述公式是ES官網的公式,這是在預設query boost為1,並且在預設term boost為1 的情況下的打分,其中

sumOfSquaredWeights =idf(t1)*idf(t1)+idf(t2)*idf(t2)+...+idf(tn)*idf(tn)

其中n為在query裡面切成term的個數,但是上面全部是在預設為1的情況下的計算,實際上的計算公式如下所


coord(q,d):

coord(q,d)是一個協調因子它的值如下:

coord(q,d)=overlap/maxoverlap
其中overlap是檢索命中query中term的個數,maxoverlap是query中總共的term個數,例如查詢詞為“無線通訊”,使用預設分詞器,如果文件為“通知他們開會”,只會有一個“通”命中,這個時候它的值就是1/4=0.25

tf(t in d):

即term t在文件中出現的個數,它的計算公式官網給出的是:

tf(t in d) = √frequency
即出現的個數進行開方,這個沒什麼可以講述的,實際打分也是如此

idf(t):

這個的意思是出現的逆詞頻數,即召回的文件在總文件中出現過多少次,這個的計算在ES中與lucene中有些區別,只有在分片數為1的情況下,與lucene的計算是一致的,如果不唯一,那麼每一個分片都有一個不同的idf的值,它的計算方式如下所示:

idf(t) = 1 + log ( numDocs / (docFreq + 1))
其中,log是以e為底的,不是以10或者以2為底,這點需要注意,numDocs是指所有的文件個數,如果有分片的話,就是指的是在當前分片下總的文件個數,docFreq是指召回文件的個數,如果有分片對應的也是在當前分片下召回的個數,這點是計算的時候與lucene不同之處,如果想驗證是否正確,只需將分片shard的個數設定為1即可。

t.getboost():

對於每一個term的權值,沒仔細研究這個項,個人理解的是,如果對一個field設定boost,那麼如果在這個boost召回的話,每一個term的boost都是該field的boost

norm(t,d):

對於field的標準化因子,在官方給的解釋是field越短,如果召回的話權重越大,例如搜尋無線通訊,一個是很長的內容,但都是包含這幾個字,但是並不是我們想要的,另外一個內容很短,但是完整包含了無線通訊,我們不能因為後面的只出現了一次就認為權重是低的,相反,權重應當是更高的,其計算公式如下所示:



其中d.getboost表明如果該文件權重越大那麼久越重要

f.getboost表明該field的權值越大,越重要

lengthnorm表示該field越長,越不重要,越短,越重要,在官方文件給出的公式中,預設boost全部為1,在此給出官方文件的打分公式:

norm(d) = 1 / √numTerms 
該值在計算的時候總是無法對上,查詢網上的資料說是在打分的時候將結果先進行壓縮,然後解壓縮,所以結果跟原始值對不上,個人理解有點像量化的過程,因為在實際explain的時候發現該值有一定的規律性

三、實際的打分explain

在實際的時候,例如搜尋“無線通訊”,如下圖所示,因為一些私人原因,將一些欄位打碼,查詢的時候設定explain為true,如下圖所示:



因為使用的是預設的分詞器,所以最後的結果是將“無線通訊”分成了四個字,並且認為是四個term來進行計算,最後將計算的結果進行相加得到最後的得分0.7605926,這個分數是“無”的得分+“線”的得分+“通”的得分+“信”的得分,四個term的得分如下圖所示:




最後的得分是0.7605926=0.118954286+0.1808154+0.14515185+0.31567,與上述符合,因為四個詞都出現了所以在這裡面的coord=1,總分數的計算知道後,我們單看每一部分的得分的計算,以“無”為例進行介紹:


其中每一個term內部分為兩部分的分數,一部分是queryweight,一部分是fieldweight,其中總分數=queryweight*fieldweight

例如此處queryweight=0.51195854,fieldWeight=0.2323514,所以總的分數就是0.118954286

queryweigth計算:

對於queryweight部分的計算分為兩個部分idf和querynorm,其中idf的值是2.8618271,這個值是如何計算的呢

idf=1+ln(1995/(309+1))=2.8618271,說明在分片四里面共有1995個文件,召回了包含“無”的309個文件,因此為這個值

querynorm部分的計算:根據上面“無”“線”“通”“信”四個的分數計算,可以看到,idf的值分別為

無:2.8618271

線:3.1053379

通:2.235371

信:2.901306

所以按照計算公式

querynorm=1 / √2.8618271*2.8618271+3.1053379*3.1053379+2.235371*2.235371+2.901306*2.901306=0.1788922

所以queryweight部分的值是0.1788922*2.8618271=0.51195854

再次總結下此處的公式:queryweight=idf*queryNorm(d)

fieldweight部分計算:

idf的計算上邊已經算過,在此不詳細敘述

tf的值是在此處出現3次,所以為√3=1.7320508

fieldnorm的值不知道如何計算,按照公式計算不出來explain的值,網上資料說是編解碼導致的,哪位朋友知道如何計算麻煩回覆下,多謝

總結下fieldweight部分的計算公式:fieldweight=idf*tf*fieldnorm=1.7320508*2.8618271*0.046875=0.2323514

所以總體的計算就是

score=queryweight*fieldweight=idf*queryNorm(d)*idf*tf*fieldnorm=coord*queryNorm(d)*tf*idf^2*fieldnorm

四、參考文件

http://www.cnblogs.com/forfuture1978/archive/2010/03/07/1680007.html

https://www.elastic.co/guide/en/elasticsearch/guide/current/scoring-theory.html#field-norm