Elasticsearch 相關度評分算法

序號 內容 鏈接地址
1 SpringBoot整合Elasticsearch7.6.1 https://blog.csdn.net/miaomiao19971215/article/details/105106783
2 Elasticsearch Filter執行原理 https://blog.csdn.net/miaomiao19971215/article/details/105487446
3 Elasticsearch 倒排索引與重建索引 https://blog.csdn.net/miaomiao19971215/article/details/105487532
4 Elasticsearch Document寫入原理 https://blog.csdn.net/miaomiao19971215/article/details/105487574
5 Elasticsearch 相關度評分算法 https://blog.csdn.net/miaomiao19971215/article/details/105487656
6 Elasticsearch Doc values https://blog.csdn.net/miaomiao19971215/article/details/105487676
7 Elasticsearch 搜索技術深入 https://blog.csdn.net/miaomiao19971215/article/details/105487711
8 Elasticsearch 聚合搜索技術深入 https://blog.csdn.net/miaomiao19971215/article/details/105487885
9 Elasticsearch 內存使用 https://blog.csdn.net/miaomiao19971215/article/details/105605379
10 Elasticsearch ES-Document數據建模詳解 https://blog.csdn.net/miaomiao19971215/article/details/105720737

一. 相關度評分算法的組成

對於Elasticsearch而言,相關度評分的計算規則通過三部分組成: boolean model,TF/IDF,Vector space model。這三個部分沒有所謂的權重,它們是平等的,計算時逐層推進

1.1 boolean model

boolean model是相關度分數計算的第一步操作。

Elasticsearch搜索時,首先根據搜索條件,過濾出符合條件的document,此時Elasticsearch不會做任何的相關度分數計算,僅僅只記錄true或false,標記document是否滿足搜索要求(對標Elasticsearch內存中的Node Query Cache區域)。

1.2 TF/IDF

TF/IDF是相關度分數計算的第二步操作。

在對搜索條件進行分詞後,Elasticsearch會根據TF/IDF算法,依託於index內所有document中,計算每一個(不可拆分的)詞條的相關度分數。

TF/IDF算法可以被拆分成TF算法,IDF算法以及length norm算法:

  1. TF: term frequency,詞頻算法。對搜索條件進行分詞後,各詞條在整個index的所有document中出現的次數越多,則權重越高。
    舉例:搜索條件爲"hello es",document1對應 {“field_test”: “hello world, I am learning es”},document2對應{“field_test”: “hello Wuhan”}。
    分析:由於搜索條件分詞後,document1包含了2個關鍵詞,而document2只包含了1個關鍵詞,因此在計算TF這一項相關度分數算法指標時,document1比document2高。

  2. IDF: inverse document frequency,逆文本頻率指數算法。對搜索條件進行分詞後,統計各詞條在所有(已過濾的)document中出現的次數,出現的次數越多,詞條的特性越弱,該詞條在後續用於評定相關度分數時,起到的作用也越低。
    舉例:搜索條件爲hello es,document1對應 {“field_test”: “hello world, I am learning something new”},document2對應{“field_test”: “java es”} 其中,hello在index中出現了1000次,es出現了100次。
    分析:即便document1和document2中出現詞條的次數相同,由於"hello"的相關度評定價值比"es"低,因此,在計算IDF這項相關度算法的權重時,document1比document2低。

  3. length norm: 長度規範。對已匹配目標詞條的document而言,document的長度越長,則相關度分數閱讀。
    舉例:搜索條件爲hello es,document1對應 {“field_test”: “hello world, I am learning something new”}, document2對應{“field_test”: “heelo es”}
    分析:雖然兩個document都只包含了一個目標詞條,但document1內的無用數據比document2多,因此在計算length norm這項相關度算法的權重時,document1比document2低。

最後Elasticsearch會綜合上述三種算法,計算出每一個term對於每一個document的權重。

1.3 Vector space model

空間向量算法是相關度分數計算的第三步操作。
從TF/IDF最終的執行結果中,我們不難看出這種算法仍然不能滿足我們的需求,因爲搜索條件中往往不止有一個term,經過TF/IDF算法後,僅僅只是爲每一個(過濾後的)document計算出每一個term的相關度分數,那麼怎樣求得一個"總分"呢?貿然的對所有term分數求和肯定不好,所以空間向量算法(Vector space model)就派上用場了。

首先,我們從document出發。document由若干個term組成(忽略停用詞),通過TF/IDF算法計算後,我們可以得知每一個term在document中的權重,而不同的term又會根據自己的權重影響當前document的相關度得分。
在這裏,我們將當前document中出現的所有term的權重組合起來,形成一條向量——Document Vector
顯然,Document Vector可能會有多條。

Document = {term1, term2, …… ,termN}
Document Vector = {weight1, weight2, …… ,weightN}

接着,我們把查詢條件也看做一個document,分別爲其中的每一個詞條參考它們在所有document中的權重值計算出各自的權重值,最後組合起來,形成一條向量——Query Vector

Query = {term1, term2, …… , termN}
Query Vector = {weight1, weight2, …… , weightN}

最後,我們把所有計算出的向量(文檔向量和查詢向量)放在同一個N維空間中,如圖所示:
在這裏插入圖片描述
現在的關鍵是計算每一個Document Vector對於Query Vector的相似度。Elasticsearch認爲,若兩個向量之間的夾角越小,則相似度越高。

即: 夾角越小 -> 該角的餘弦值越大 -> 兩條向量的相似度越高 -> 最終相關度分數越高

相關度分數的計算公式如下:
在這裏插入圖片描述
若想對空間向量算法做更深入的瞭解,可以參考文章: ElasticSearch之向量空間模型算法介紹

二. Lucene中的相關度分數算法

Lucene中的相關度分數算法,相當於整個相關度評分算法的第二步——TD/IDF算法。
在Lucene中,使用practical scoring function來計算query對某一個document的相關度分數。該函數會使用以下方式計算:

score(q,d)  =  
    queryNorm(q)  
    · coord(q,d)    
    · ∑ (           
        tf(t in d)   
        · idf(t)2      
        · t.getBoost() 
        · norm(t,d)    
    ) (t in q)

這裏面涉及到了許多函數,它們的功能大致如下:

  1. score(q,d)
    官方解釋: score(q,d)is the relevance score of document d for query q.
    這個函數能夠計算出一個query(q)針對一個document(d)的最終相關度分數。
  2. queryNorm(q)
    官方解釋: queryNorm(q) is the query normalization factor(new).
    這個函數用來讓document的最終相關度得分處於一個合理的區間,比如document1的分數爲1000,而document2的分數卻只有0.1,像這種評分跨度就太大了,不適合做最終評分數統計。算法大概是1/√sumOfSquaredWeights,其中sumOfSquaredWeights是∑公式結果,我們對這個結果做平方根計算,再被1除,得到的就是queryNorm()的最終結果。
  3. coord(q,d)
    官方解釋: coord(q,d) is the coordination factor (new).
    簡單來說,就是對更加匹配query的document進行分數上的成倍獎勵。比如: query搜索條件是hello java spark,如果某個document中只有hello這個term匹配,假設給定一個term的匹配分數爲1.5,那麼通過coord算法計算出的分數爲: 1.5 x 1 / 3 = 0.5。如果另一個document中有hello和world匹配,假設匹配兩個term時,每個term給定的分數是3,那麼通過coord算法計算出的分數爲: 3 * 2 / 3 = 2。依次類推。涉及coord算法的理由便是爲了給那些更匹配query的document給予成倍的分數獎勵。

  4. 官方解釋: The sum of the weights for each term t in the query q for document d.
    將搜索條件分詞後的每一個term對document的相關度分數進行求和,相當於向量空間算法。比如: query搜索條件爲hello world,分詞後可以得到"hello"和"world"這兩個詞條。接着,分別對每一個document計算這兩個詞條的相關度分數,最後求和。
  5. tf()
    官方解釋: tf(t in d) is the term frequency for term t in document d.
    計算每一個term的對document的分數。本質上是TF算法。
  6. idf()
    官方解釋: idf(t) is the inverse document frequency for term t.
    計算query搜索條件分詞後的詞條在逆文本頻率指數中的得分。本質上是IDF算法。
  7. getBoost()
    官方解釋: t.getBoost() is the boost that has been applied to the query (new).
    獲取搜索條件中設置的權重,在計算相關度分數時,若搜索條件匹配成功,則乘以對應的權重。
  8. norm(t, d)
    官方解釋: norm(t,d) is the field-length norm, combined with the index-time field-level boost, if any. (new).
    根據field的長度來計算document的得分。本質上是norm-length算法。

三. 優化相關度分數計算的方式(推薦使用☆☆☆☆☆)

3.1 query-time boost

在搜索時,通過對搜索條件設置boost,實現條件匹配時分數倍增的目的。

GET /index_name/_search
{
  "query": {
    "bool": {
      "should": [
        {
          "match": {
            "field1": {
              "query": "value1",
              "boost": 2
            }
          }
        },
        {
          "match": {
            "field2": {
              "query": "value2",
              "boost": 4
            }
          }
        }
      ]
    }
  }
}

3.2 negative boost

在搜索時,通過對搜索條件設置negative boost,實現匹配某些條件時分數降低的目的。

比如希望搜索出包含java的數據,但不太想搜索出包含elasticsearch的數據。如果貿然使用must和must_not,會造成同時包含java和elasticsearch的數據被過濾掉的後果。

此時,我們可以使用negative boost來解決這個問題。negative boost會降低elasticsearch詞條在每個document中相關度分數計算時的比值,從而變相的提高了java詞條的比值,實現更加合理的排序。

GET /index_name/_search
{
  "query": {
    "boosting": {
      "positive": {
        "match": {
          "field1": "java"
        }
      },
      "negative": {
        "match": {
          "field1": "elasticsearch"
        }
      },
      "negative_boost": 0.2
    }
  }
}

注意:

  1. "positive"代表正向計算相關度分數,默認權重爲1(不能修改,比如像3.1節中使用boost手動指定權重)。"negative"代表反向計算相關度分數,它的權重指由"negative_boost"指定。
  2. negative boost能夠"拖垮"整個document的相關度分數。

3.3 constant score

使用constant_score會忽略相關度分數的計算過程,所有document的相關度分數都是1。在Elasticsearch6.x版本以後,constant score內不能使用query語法,只能通過filter來實現數據的過濾,但filter本身恰好又是不計算相關度分數的,因此藉助constant score來影響相關度分數的做法漸漸不再被使用。

GET /index_name/_search
{
  "query": {
    "bool": {
      "should": [
        {
          "constant_score": {
            "filter": {
              "term": {
                "field1": "java"
              }
            }
          }
        },
        {
          "constant_score": {
            "filter": {
              "terms": {
                "field1": ["elasticsearch"]
              }
            }
          }
        }
      ]
    }
  }
}

四. 使用function score自定義相關度分數算法

4.1 field_value_factor

Elasticsearch中允許自定義相關度分數算法的計算函數,這個函數計算出的結果可以參與到最終的相關度分數計算中,甚至可以直接作爲最終的相關度分數(但不會影響boolean model,TF/IDF以及Vector Space Model的執行過程)。

舉例:

POST /index_name/_bulk
{"index" : { "_id" : "1" }}
{"fc" : 10, "f" : "hello world"}
{"index" : { "_id" : "2" }}
{"fc" : 20, "f" : "hello java"}
{"index" : { "_id" : "3" }}
{"fc" : 5, "f" : "hello spark"}
{"index" : { "_id" : "4" }}
{"fc" : 15, "f" : "hello bye bye"}
{"index" : { "_id" : "5" }}
{"fc" : 13, "f" : "hi world"}

GET /index_name/_search
{
  "query": {
    "function_score": {
      "query": {
        "match": {
          "f": "java spark"
        }
      },
      "field_value_factor": {
        "field": "fc",
        "modifier": "log2p", 
        "factor": 0.5
      },
      "boost_mode": "sum",
      "max_boost": 0.8
    }
  }
}

如果field_value_factor中只寫了"field",那麼Elasticsearch會在query match中計算出的相關度分數的基礎上直接乘以document中對應"field"字段的值。比如直接使用query match “f”: "java spark"時,得到的document的分數爲1.43,而fc的值爲20,那麼組合後計算出的相關度分數爲1.43 x 20 = 28.6。

modifier是針對field的計算公式。Elasticsearch內部提供了大量的計算公式,比如ln、ln1p、ln2p、log1p、log2p等等。舉個例子,log2p對應的公式爲: log以2爲底,2+number_of_votes的對數,number_of_votes就是document中對應自定義相關度分數計算字段的值。最終得到的結果再去和前面query match計算出的值相乘。

factor可以進一步影響相關度分數的計算, log(1 + factor * number_of_votes)。

前面都是用自定義相關度分數乘以query match的值作爲最終的相關度分數,倘若不想使用乘法,我們還可以選用boost_mode參數。
boost_mode可以選擇函數: max(最大值)、min(最小值)、avg(平均值)、multiply(乘法[默認值])、replace(替換)、sum(求和)。

max_boost,限制自定義相關度分數字段最終計算出的數值不得超過max_boost指定的值,如果超過,則直接使用max_boost的值。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章