Elasticsearch從入門到放棄:淺談算分

Jackeyzhe發表於2021-01-27

今天來聊一個 Elasticsearch 的另一個關鍵概念——相關性算分。在查詢 API 的結果中,我們經常會看到 _score 這個欄位,它就是用來表示相關性算分的欄位,而相關性就是描述一個文件和查詢語句的匹配程度。

打分的本質其實就是排序,Elasticsearch 會把最符合使用者需求的文件排在最前面。

在 Elasticsearch 5.0 之前,相關性算分演算法採用的是 TF-IDF 演算法,而在5.0之後採用的是 BM 25 演算法。聽到這也許你會比較疑惑,想知道這兩個演算法到底是怎麼樣的。別急,下面我們來具體瞭解一下。

TF-IDF

首先來看字面意思,TF 是 Term Frequency 的縮寫,也就是詞頻。IDF 是 Inverse Document Frequency 的縮寫,也就是逆文件頻率。

詞頻

詞頻比較好理解,就是要搜尋的目標單詞在文件中出現的頻率。算式為檢索詞出現的次數除以文件的總字數。最簡單的相關性演算法就是將檢索詞進行分詞後對他們的詞頻進行相加。例如,我要搜尋“我的演算法”,其相關性就可以表示為:

TF(我) + TF(的) + TF(演算法)

但這裡也有些問題,像“的”這樣的詞,雖然出現的次數很多,但是對貢獻的相關度幾乎沒有用處。所以在考慮相關度時不應該考慮他們,對於這類詞,我們統稱為 Stop Word。

逆文件頻率

聊完了 TF,我們再來看看 IDF,在瞭解逆文件頻率之前,首先需要知道什麼是文件頻率,也就是 DF。

DF 其實是檢索詞在所有文件中出現的頻率。例如,“我”在較多的文件中出現,“的”在非常多的文件中都會出現,而“演算法”只會在較少的文件中出現。這就是文件頻率,那逆文件頻率,簡單理解就是:

log(全部文件數 / 檢索詞出現過的文件總數)

針對上面的例子,我們將它更具體的呈現一下。假設我們文件總數為1億,出現“我”字的文件有5000萬,那麼它的 IDF 就是 log(2) = 1 。“的”在1億文件中都有出現,IDF 就是 log(1) = 0,而演算法只在20萬個文件中出現,那麼它的 IDF 就是 log(500) ,大約是8.96。

由此可見,IDF 越大的單詞越重要。

好了,現在各位 TF 和 IDF 應該都有一定的瞭解了,那麼 TF-IDF 本質上就是對 TF 進行一個加權求和。

TF(我) * IDF(我) + TF(的) * IDF(的) + TF(演算法) * IDF(演算法)

BM 25

BM25可以看作是對 TF-IDF 的一個優化,其優化的效果是,當 TF 無限增加時, TF-IDF 的結果會隨之增加,而 BM 25 的結果會趨近於一個數值。這就限制了一個 term 對於檢索詞整體相關性的影響。

BM25演算法的公式如下:

BM25

想要詳細瞭解BM25演算法的同學可以參考這篇文章BM25 The Next Generation of Lucene Relevance

Explain API

如果想要了解一個查詢是如何進行打分的,我們可以使用 Elasticsearch 提供的 Explain API,其用法非常簡單,只需要在引數中增加

"explain": true

也可以在 path 中增加 _explain,例如:

curl -X GET "localhost:9200/my-index-000001/_explain/0?pretty" -H 'Content-Type: application/json' -d'
{
  "query" : {
    "match" : { "message" : "elasticsearch" }
  }
}
'

這時,返回結果中就會有一個 explanation 欄位,用來描述具體的算分過程。

小結

關於 Elasticsearch 的算分,相信各位也有一個初步的認識了,如果感興趣的話也可以自己進行更加深入的研究,也歡迎各位和我一起交流。

相關文章