[Elasticsearch] 控制相關度 (五) - function_score查詢及field_value_factor,boost_mode,max_mode參數

本章翻譯自Elasticsearch官方指南的Controlling Relevance一章。html


 

function_score查詢

function_score查詢是處理分值計算過程的終極工具。它讓你可以對全部匹配了主查詢的每份文檔調用一個函數來調整甚至是徹底替換原來的_score。git

實際上,你能夠經過設置過濾器來將查詢獲得的結果分紅若干個子集,而後對每一個子集使用不一樣的函數。這樣你就可以同時得益於:高效的分值計算以及可緩存的過濾器。github

它擁有幾種預先定義好了的函數:json

weight緩存

對每份文檔適用一個簡單的提高,且該提高不會被歸約:當weight爲2時,結果爲2 * _score。dom

field_value_factorelasticsearch

使用文檔中某個字段的值來改變_score,好比將受歡迎程度或者投票數量考慮在內。ide

random_score函數

使用一致性隨機分值計算來對每一個用戶採用不一樣的結果排序方式,對相同用戶仍然使用相同的排序方式。工具

衰減函數(Decay Function) - linear,exp,gauss

將像publish_date,geo_location或者price這類浮動值考慮到_score中,偏好最近發佈的文檔,鄰近於某個地理位置(譯註:其中的某個字段)的文檔或者價格(譯註:其中的某個字段)靠近某一點的文檔。

script_score

使用自定義的腳原本徹底控制分值計算邏輯。若是你須要以上預約義函數以外的功能,能夠根據須要經過腳本進行實現。

沒有function_score查詢的話,咱們也許就不能將全文搜索獲得分值和近因進行結合了。咱們將不得不根據_score或者date進行排序;不管採用哪種都會抹去另外一種的影響。function_score查詢讓咱們可以將二者融合在一塊兒:仍然經過全文相關度排序,可是給新近發佈的文檔,或者流行的文檔,或者符合用戶價格指望的文檔額外的權重。你能夠想象,一個擁有全部這些功能的查詢看起來會至關複雜。咱們從一個簡單的例子開始,按部就班地對它進行介紹。

 

 

根據人氣來提高(Boosting by Popularity)

假設咱們有一個博客網站讓用戶投票選擇他們喜歡的文章。咱們但願讓人氣高的文章出如今結果列表的頭部,可是主要的排序依據仍然是全文搜索分值。咱們能夠經過保存每篇文章的投票數量來實現:

PUT /blogposts/post/1
{
  "title": "About popularity", "content": "In this post we will talk about...", "votes": 6 }

在搜索期間,使用帶有field_value_factor函數的function_score查詢將投票數和全文相關度分值結合起來:

GET /blogposts/post/_search
{
  "query": { "function_score": { "query": { "multi_match": { "query": "popularity", "fields": [ "title", "content" ] } }, "field_value_factor": { "field": "votes" } } } }

function_score查詢會包含主查詢(Main Query)和但願適用的函數。先會執行主查詢,而後再爲匹配的文檔調用相應的函數。每份文檔中都必須有一個votes字段用來保證function_score可以起做用。

在前面的例子中,每份文檔的最終_score會經過下面的方式改變:

new_score = old_score * number_of_votes

它獲得的結果並很差。全文搜索的_score一般會在0到10之間。而從下圖咱們能夠發現,擁有10票的文章的分值大大超過了這個範圍,而沒有被投票的文章的分值會被重置爲0。

modifier

爲了讓votes值對最終分值的影響更緩和,咱們可使用modifier。換言之,咱們須要讓頭幾票的效果更明顯,其後的票的影響逐漸減少。0票和1票的區別應該比10票和11票的區別要大的多。

一個用於此場景的典型modifier是log1p,它將公式改爲這樣:

new_score = old_score * log(1 + number_of_votes)

log函數將votes字段的效果減緩了,其效果相似下面的曲線:

使用了modifier參數的請求以下:

GET /blogposts/post/_search
{
  "query": { "function_score": { "query": { "multi_match": { "query": "popularity", "fields": [ "title", "content" ] } }, "field_value_factor": { "field": "votes", "modifier": "log1p" } } } }

可用的modifiers有:none(默認值),log,log1p,log2p,ln,ln1p,ln2p,square,sqrt以及reciprocal。它們的詳細功能和用法能夠參考field_value_factor文檔

factor

能夠經過將votes字段的值乘以某個數值來增長該字段的影響力,這個數值被稱爲factor:

GET /blogposts/post/_search
{
  "query": { "function_score": { "query": { "multi_match": { "query": "popularity", "fields": [ "title", "content" ] } }, "field_value_factor": { "field": "votes", "modifier": "log1p", "factor": 2 } } } }

添加了factor將公式修改爲這樣:

new_score = old_score * log(1 + factor * number_of_votes)

當factor大於1時,會增長其影響力,而小於1的factor則相應減少了其影響力,以下圖所示:

boost_mode

將全文搜索的相關度分值乘以field_value_factor函數的結果,對最終分值的影響可能太大了。經過boost_mode參數,咱們能夠控制函數的結果應該如何與_score結合在一塊兒,該參數接受下面的值:

  • multiply:_score乘以函數結果(默認狀況)
  • sum:_score加上函數結果
  • min:_score和函數結果的較小值
  • max:_score和函數結果的較大值
  • replace:將_score替換成函數結果

若是咱們是經過將函數結果累加來獲得_score,其影響會小的多,特別是當咱們使用了一個較低的factor時:

GET /blogposts/post/_search
{
  "query": { "function_score": { "query": { "multi_match": { "query": "popularity", "fields": [ "title", "content" ] } }, "field_value_factor": { "field": "votes", "modifier": "log1p", "factor": 0.1 }, "boost_mode": "sum" } } }

上述請求的公式以下所示:

new_score = old_score + log(1 + 0.1 * number_of_votes)

max_boost

最後,咱們可以經過制定max_boost參數來限制函數的最大影響:

GET /blogposts/post/_search
{
  "query": { "function_score": { "query": { "multi_match": { "query": "popularity", "fields": [ "title", "content" ] } }, "field_value_factor": { "field": "votes", "modifier": "log1p", "factor": 0.1 }, "boost_mode": "sum", "max_boost": 1.5 } } }

不管field_value_factor函數的結果是多少,它毫不會大於1.5。

NOTE

max_boost只是對函數的結果有所限制,並非最終的_score。

相關文章
相關標籤/搜索