ES學習——ES評分簡單介紹

當我們能使用match來搜索匹配數據的時候,es會給每一個文檔進行評分(匹配度),並根據評分的大小對結果文檔進行排序。

介紹

es的實時評分機制是基於 Lucene 的基礎上實現的,最常見的是 TF/IDFBM25這兩種評分模型。

TF-IDF屬於向量空間模型,而BM25屬於概率模型,但是他們的公式可能並沒有你想象的那麼大差距。兩種相似度模型都使用idf方法和tf方法的某種乘積來定義單個詞項的權重,然後把和查詢匹配的詞項的權重相加作爲整篇文檔的分數。

對於這兩種算法的詳細介紹以及區別大家可以參考:

  1. https://en.wikipedia.org/wiki/Okapi_BM25
  2. https://en.wikipedia.org/wiki/Tf–idf

在es5.0版本之前使用了TF/IDF算法實現,而在5.0之後默認使用BM25方法實現。

作爲開發,我們可以不需要了解非常深入的瞭解公式的由來,但也要做到公式的組成和每個參數的含義。

例子

下面是一個普通的查詢:

PUT /test/test1/1
{"title":"hallo,books"}
PUT /test/test1/2
{"title":"hallo,books boy"}
PUT /test/test1/3
{"title":"hallo hallo,hi hi hi hi"}
PUT /test/test1/4
{"title":"hallo hallo,hi hi hi hi"}
PUT /test/test1/5
{"title":"hi hi hi hi"}

GET /test/test1/_search
{
  "query": {
    "match": {
      "title": "hallo hi"
    }
  }
}

在搜索的結果中有一個_score字段,代表了es給文檔的評分,默認的排序規則是根據這個字段的大小進行排序,越大則出現在越前面。

當我們搜索一個單詞或者一個詞組乃至一句話的時候,es先會通過Analyzer分析器拆成多個term(ES學習——分析器和自定義分析器),然後在對每一個term進行BM25公式評分,最後把每一個term的評分進行加權求和,就是最後的得分。

例如,我們搜索hallo hi,es通過對應的默認解析器拆分成hallohi,分別求出分數score(hallo)和score(hi):
總得分Score=score(hallo)+score(hi)。

和sql相似,我們可以通過在搜索條件中添加explain=true,來查看具體的得分過程。

GET /test/test1/_search?explain=true
{
  "query": {
    "match": {
      "title": "hallo hi"
    }
  }
}

##以下通過篩選,過濾了一些無用的信息

{
        "_shard": "[test][0]",1"_score": 1.202173,2"_source": {
          "title": "hallo hallo,hi hi hi hi"3},
        "_explanation": {
          "value": 1.202173,
          "description": "sum of:",4"details": [
            {
              "value": 0.3530123,5"description": "weight(title:hallo in 2) [PerFieldSimilarity], result of:",
              "details": [
                {
                  "value": 0.3530123,7"description": "score(doc=2,freq=2.0 = termFreq=2.0\n), product of:",
                  "details": [
                    {
                      "value": 0.2876821,
                      "description": "idf, computed as log(1 + (docCount - docFreq + 0.5) / (docFreq + 0.5)) from:",
                      "details": [
                        {
                          "value": 4,
                          "description": "docFreq"
                        },
                        {
                          "value": 5,
                          "description": "docCount"
                        }
                      ]
                    },
                    {
                      "value": 1.2270917,8"description": "tfNorm, computed as (freq * (k1 + 1)) / (freq + k1 * (1 - b + b * fieldLength / avgFieldLength)) from:",
                      "details": [
                        {
                          "value": 2,
                          "description": "termFreq=2.0"
                        },
                        {
                          "value": 1.2,
                          "description": "parameter k1"
                        },
                        {
                          "value": 0.75,
                          "description": "parameter b"
                        },
                        {
                          "value": 4.2,
                          "description": "avgFieldLength"
                        },
                        {
                          "value": 6,
                          "description": "fieldLength"
                        }
                      ]
                    }
                  ]
                }
              ]
            },
            {
              "value": 0.84916073,6"description": "weight(title:hi in 2) [PerFieldSimilarity], result of:"
              ##省略和 hallo的計算方式類似
            }
          ]
        }
      }

從最外層結構往裏分析:
【1】:代表文檔的分片,[test][0],在es中每一個分片評分都是單獨計算的
【2】【3】:代表最後的分數和文檔
【4】:總的分數是1.202173,sum of是默認的加權平均,把hallo的分數(0.3530123)+hi的分數(0.84916073)
【5】【6】:分表表示hallo的評分和hi的評分。其description描述的很明白:weight(title:hallo in 2)
【7】【8】:hallo的評分是由【7】(idf)*【8】(tfNorm)得出
【7】:idf(下面介紹)=log(1 + (docCount - docFreq + 0.5) / (docFreq + 0.5))
【8】:tfNorm=(freq * (k1 + 1)) / (freq + k1 * (1 - b + b * fieldLength / avgFieldLength))

公式介紹(BM25)

歸納一下上面的公式:
score=Σ(IDFtfNorm) score = \Sigma(IDF*tfNorm)
參考,BM25與TF/IDF的區別

IDF (inverse document frequency):逆文檔頻率,是指一個詞在文檔中出現的次數越多,則他的權值相對越多。例如常用的詞and 或 or 或 a在文檔中出現的次數非常多,相對於用戶而言重要性很小,但是elasticSearch等不常見的詞進行搜索的時候相對於用戶來說,權重應該更大。

IDF

在_explanation中也已經寫明瞭IDF的計算公式:
IDF=log(1+(docCountdocFreq+0.5)docFreq+0.5) IDF = \log(\frac{1 + (docCount - docFreq + 0.5)}{docFreq + 0.5})

其中docCount代表該分片總的文檔數量數量,docFreq代表有這個分詞的文檔數量。
在例子中,總共的文檔數爲5,包含hallo的文檔數爲4,所以docFreq=4,docCount=5。IDF最終算出來爲0.2876821,且在同一分片中所有的文檔的IDF且相同。

tfNorm

tfNorm代表此term在此文檔中的重要程度,在此doc中出現次數越多,越重要;並且文檔的長度越短,也見解說明改term在此doc中越重要。
具體公式:
tfNorm=freq(k1+1)freq+k1(1b+bfieldLengthavgFieldLength) tfNorm=\frac{freq * (k1 + 1)} {freq + k1 * (1 - b + b * \frac{fieldLength}{avgFieldLength})}

其中:
freq:在文檔中出現的次數
k1:爲調優參數,固定值,默認1.2,合理的值需要依賴文檔的數據。
b:爲調優參數,固定值,默認爲0.75,合理的值需要依賴文檔的數據。
fieldLength:是滿足查詢條件的doc的filed的長度
avgFieldLength:是滿足查詢條件的所有doc的filed的長度.

注意點

評分都是以分片爲單位的,若兩個文檔分佈在不同的分片,會出現即使內容完全相同但是分數有差異的情況(IDF的docCount和docFreq有區別)或者出現更加符合我們心裏預期的文檔分數反而較低的情況。

方案:

  1. 把結構相似的文檔通過route到一個分片上。個人認爲若文檔種類差異較大可以使用這種方法,但是會出現分片數據不均勻的問題。
  2. 自定義評分處理。有公式看出IDF只與出現次數和文檔總數有關,在一個分片中,次數和文檔總數是固定的,在全局中也是一樣。 設置忽略IDF。 但是這種方法,在多個term查詢的時候,相當於忽略了IDF對分數的影響。
  3. 業務上可以容忍,不做修改。當文檔的基數很大,且文檔分配很均勻的時候,兩個相同的文檔分數的差異會相對減少。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章