1. 程式人生 > >Elasticsearch2.x 全文檢索之——文件匹配度

Elasticsearch2.x 全文檢索之——文件匹配度

什麼是文件匹配度?

在ES中執行一個搜尋請求在預設情況下搜尋的結果集是按照匹配度倒序排列。但是什麼是文件匹配度?它是如何被計算的呢? 每個文件的匹配度評分在es中被表示為一個浮點型的正數——“_score”,文件的_score評分越高,文件與搜尋詞的匹配度越大。 在查詢中一個查詢子句會為每一個文件生成一個_score,文件評分的計算依賴於具體查詢子句的型別,不同的查詢子句被用在不同的搜尋場景中,比如:一個fuzzy查詢的_score表示拼寫所找到的關鍵詞和原始搜尋請求中的詞的相似度,一個terms查詢的_score表示我們查詢的詞在文件中所佔的百分比。那麼,我們通常所說的查詢字串與文件的匹配演算法是什麼呢? 在Elasticsearch中標準的相似度演算法叫做 term freqyency/inverse document frequency(也叫做TF/IDF),該演算法是在Lucene中實現,以下是Lucene計算文件評分的公式:

TF-IDF演算法主要基於以下幾個引數:
Term frequency(詞頻)

詞頻的含義是:詞條在查詢欄位上出現的頻率,出現的次數越多,相關度越大。比如,在文件A中的某個欄位上一個詞出現了5次比文件B中同一個欄位同一個詞出現1次的相關度要大

定義:詞頻(TF) =  某個詞在某一文件中出現的次數

Inverse document frequency(逆文件頻率)

逆文件頻率的含義是:詞條在整個索引上出現的頻率,出現的次數越多,相關度越低,詞條出現在更多的文件中那麼該詞條的權重將會更低(注:如果一個詞在索引中存在於大多數的文件中說明該詞是一個“公共詞”,因此權重會更低)

定義:逆文件頻率(IDF) = ln(numDocs / (docFreq + 1)) + 1,這裡的ln表示以自然數e為底的對數函式,numDocs是索引中總文件數,docFreq是查詢詞所出現的文件數

Field-length norm(欄位長度標準化)
欄位長度標準化的含義是:表示欄位所包含詞條的數量,詞條數數越多相關度越低。比如,同一個詞出現在title中比出現在content中的相關度要大。

在單個查詢中將會結合TF/IDF評分和其他一些因素來完成打分。比如在短語查詢(query_phrase)中詞的先後順序,或者在fuzzy查詢中搜索詞和匹配詞的相關度(編輯距離)

相關度不僅僅被用在全文檢索中,還被用在 yes/no 查詢中(如range,term查詢等),更多的查詢子句被匹配那麼相關度評分_score越高。

當執行一個複雜的多子句查詢時(比如bool查詢),每個查詢子句會計算出_score並最終被合併到全域性的_score上。

在一個查詢中我們可以使用explain引數來檢視文件得分如何被計算出來的(這個引數會帶來額外的效能開銷,在生產環境必須禁止,該引數僅用於debug),看看下面的例子如使用該引數:

GET /_search?explain 
{
   "query"   : { "match" : { "tweet" : "honeymoon" }}
}
該查詢執行的結果裡會在每一個文件中都會嵌入一段用於表明該文件得分是如何被計算的Json,如:
"_explanation": { 
   "description": "weight(tweet:honeymoon in 0)
                  [PerFieldSimilarity], result of:",
   "value":       0.076713204,
   "details": [
      {
         "description": "fieldWeight in 0, product of:",
         "value":       0.076713204,
         "details": [
            {  
               "description": "tf(freq=1.0), with freq of:",
               "value":       1,
               "details": [
                  {
                     "description": "termFreq=1.0",
                     "value":       1
                  }
               ]
            },
            { 
               "description": "idf(docFreq=1, maxDocs=1)",
               "value":       0.30685282
            },
            { 
               "description": "fieldNorm(doc=0)",
               "value":        0.25,
            }
         ]
      }
   ]
}
上面的總得分0.076713204 = 1 * 0.30685282 * 0.25

其中IDF(docFreq=1,maxDocs=1) = ln(1 / (1 + 1)) + 1 = 0.30685282
其中fieldNorm = lengthNorm = 1 / sqrt(1 + 3) = 0.25