Elasticsearch自定義文檔得分并排序

大多數(shù)情況下郑诺,我們需要對查詢結(jié)果排序,比方說按最新時間降序飞涂、按金額降序等。我們只需要對相應(yīng)的字段 sort 即可梁呈。但有時候也會出現(xiàn)一些復(fù)雜的情況,比方說有A寻咒、B、C、D柑肴、E類數(shù)據(jù),他想讓你給這類數(shù)據(jù)重新定義優(yōu)先級秽荞,按照B扬跋、E、D朴上、A、C的順序展示衣撬,并且每類數(shù)據(jù)內(nèi)部按時間降序。然而最近我們也提出了一個類似這樣的需求靠粪,查閱相關(guān)文檔后,發(fā)現(xiàn)Elasticsearch里的function_socre函數(shù)可以實(shí)現(xiàn)這一功能畔乙, 遂將此學(xué)習(xí)內(nèi)容做一個記錄。

先來看看function_score是什么牍鞠,它能做什么?根據(jù)官網(wǎng)的原話:

The function_score allows you to modify the score of documents that are retrieved by a query.

function_score允許你修改通過查詢檢索出來的文檔的得分店读。

下面我們通過一些簡單的例子來看看function_score怎么使用。

function_score可以為所有文檔生成一個隨機(jī)分?jǐn)?shù):

GET us_police_shooting_index/_search
{
  "query": {
    "function_score": {
      "query": {
        "match_all": {}
      },
      "random_score": {},
      "boost": 5,
      "boost_mode": "min"
    }
  }
}

還可以組合不同的過濾條件,設(shè)置權(quán)重:

GET us_police_shooting_index/_search
{
  "query": {
    "function_score": {
      "query": {
        "match_all": {}
      },
      "functions": [
        {
          "filter": {
            "match": {
              "race": "Asian"
            }
          },
          "weight": 8
        },
        {
          "filter": {
            "match": {
              "race": "White"
            }
          },
          "weight": 2
        }
      ],
      "max_boost": 20,
      "score_mode": "max",
      "boost_mode": "sum",
      "min_score": 3
    }
  }
}

如果functions里的filter未給出,那么將會匹配所有文檔朋鞍,相當(dāng)于 "match_all":{}

我們看看function_score為我們提供了哪些參數(shù):

  • score_mode指定了該如何去合并每個文檔生成的評分:
score_mode 定義
multiply 函數(shù)結(jié)果相乘(默認(rèn))
sum 函數(shù)結(jié)果相加
avg 函數(shù)結(jié)果的平均值
first 使用首個函數(shù)的結(jié)果做為最終結(jié)果
max 函數(shù)結(jié)果的最大值
min 函數(shù)結(jié)果的最小值
  • boost_mode可以用來控制函數(shù)與查詢評分_score合并后的結(jié)果:
boost_mode 定義
multiply 評分_score與函數(shù)值的乘積(默認(rèn))
replace 評分_score會被忽略宇葱,僅使用函數(shù)值
sum 評分_score與函數(shù)值之和
avg 評分_score與函數(shù)值的平均值
max 評分_score與函數(shù)值間的最大值
min 評分_score與函數(shù)值間的最小值
  • min_score可以設(shè)置為期望分?jǐn)?shù)的閾值诸尽,能夠排出不符合特定分?jǐn)?shù)閾值的文檔。
  • max_boost可以限制函數(shù)的最大效果际看,但是不會對最終的評分_score產(chǎn)生直接的影響仿村。

function_score還提供幾種類型的評分函數(shù):

  • script_score:腳本評分函數(shù)允許計算自定義查詢的評分衣迷,腳本表達(dá)式需使用文檔中的數(shù)值字段云矫。查詢的分?jǐn)?shù)將與腳本評分的結(jié)果相乘,如果不想使用這種方式,可通過設(shè)置"boost_mode":"replace"來禁止腮敌。

    GET /_search
    {
      "query": {
        "function_score": {
          "query": {
            "match": { "message": "elasticsearch" }
          },
          "script_score": {
            "script": {
              "source": "Math.log(2 + doc['likes'].value)"
            }
          }
        }
      }
    }
    
    GET /_search
    {
      "query": {
        "function_score": {
          "query": {
            "match": { "message": "elasticsearch" }
          },
          "script_score": {
            "script": {
              "params": {
                "a": 5,
                "b": 1.2
              },
              "source": "params.a / Math.pow(params.b, doc['likes'].value)"
            }
          }
        }
      }
    }
    
  • weight:權(quán)重函數(shù)可以將評分與weight值相乘录淡,weight的值是float類型刨裆。

  • random_score:隨機(jī)評分函數(shù)會產(chǎn)生一個0到1之間的分?jǐn)?shù),當(dāng)種子feed值相同時,生成的隨機(jī)結(jié)果是一致的慈俯。

    GET /_search
    {
      "query": {
        "function_score": {
          "random_score": {
            "seed": 10,
            "field": "_seq_no"
          }
        }
      }
    }
    
  • field_value_factor:通過使用文檔中的某個字段來影響評分。如果這個字段有多個值刑峡,那么只有第一個值才被用來計算評分突梦。

    GET /_search
    {
      "query": {
        "function_score": {
          "field_value_factor": {
            "field": "likes",
            "factor": 1.2,
            "modifier": "sqrt",
            "missing": 1
          }
        }
      }
    }
    # 上面評分的計算相當(dāng)于 sqrt(1.2 * doc['likes'].value)
    
    • filed:文檔中提取的字段宫患。
    • factor:字段值乘以的可選因子娃闲,默認(rèn)是1卷哩。
    • modifiernone, log, log1p, log2p, ln, ln1p, ln2p, square, sqrt, reciprocal捌年。默認(rèn)值是 none.
  • decay_functions:衰減函數(shù)的功能與范圍查詢類似,但它具有更平滑的邊緣褒颈。衰減函數(shù)支持gausslinearexp中任意一種函數(shù)揩慕,并且都能接收以下參數(shù):

    • origin:中心點(diǎn)或字段可能的最佳值,落在原點(diǎn)origin上的文檔評分_score為滿分1.0劲藐。字段必須是數(shù)值、日期或地理坐標(biāo)類型。
    • scale:衰減率,一個文檔從原點(diǎn)origin下落時百新,評分_score改變的速度形庭。
    • offset:以原點(diǎn)origin為中心點(diǎn)斟珊,為其設(shè)置一個非零的offset覆蓋一個范圍,而不只是單個原點(diǎn)。在范圍-offset <= origin <= +offset內(nèi)的所有評分_score都是1.0勤庐。
    • decay:從原點(diǎn)origin衰減到scale所得的評分_score,默認(rèn)是0.5
    GET /_search
    {
      "query": {
        "function_score": {
          "functions": [
            {
              "gauss": {
                "price": {
                  "origin": "0",
                  "scale": "20"
                }
              }
            },
            {
              "gauss": {
                "location": {
                  "origin": "11, 12",
                  "scale": "2km"
                }
              }
            }
          ],
          "query": {
            "match": {
              "properties": "balcony"
            }
          },
          "score_mode": "multiply"
        }
      }
    }
    

官方文檔有這么一張圖片說明了三個函數(shù)的衰減曲線形狀:


Screen Shot 2020-08-16 at 11.46.44.png

以上就是function_score函數(shù)的大部分內(nèi)容。現(xiàn)在我們來具體實(shí)現(xiàn)文章開頭提到的一個需求。我準(zhǔn)備了一份不同歌手的歌曲發(fā)行時間的測試數(shù)據(jù)弧圆,主要字段有歌手名name、歌曲名song、發(fā)行時間publishDate船庇。

首先我們先按歌手名降序达吞,發(fā)行時間升序吞鸭,很容易能寫出下面的DSL語句:

GET music_index/_search
{
  "query": {
    "match_all": {}
  },
  "sort": [
    {
      "name.keyword": {
        "order": "desc"
      },
      "publishDate.keyword": {
        "order": "asc"
      }
    }
  ]
}

現(xiàn)在我想按許冠杰、鄧麗君、陳百強(qiáng)的順序進(jìn)行展示漓藕,并且各自的歌曲按發(fā)行時間升序诀蓉,function_score就體現(xiàn)出它的作用了:

GET music_index/_search
{
  "query": {
    "function_score": {
      "query": {
        "match_all": {}
      },
      "functions": [
        {
          "filter": {
            "term": {
              "name.keyword": "許冠杰"
            }
          },
          "weight": 5
        },
        {
          "filter": {
            "term": {
              "name.keyword": "鄧麗君"
            }
          },
          "weight": 4
        },
        {
          "filter": {
            "term": {
              "name.keyword": "陳百強(qiáng)"
            }
          },
          "weight": 3
        }
      ]
    }
  },
  "sort": [
    {
      "_score": {
        "order": "desc"
      },
      "publishDate.keyword": {
        "order": "asc"
      }
    }
  ]
}

由于查詢文檔太長,我就不粘貼查詢結(jié)果了碟联。感興趣的可以自己動手嘗試嘗試玄帕,如果需要測試數(shù)據(jù)委刘,公眾號回復(fù)0816即可獲取相關(guān)文件。

相關(guān)鏈接:
https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-function-score-query.html
https://www.elastic.co/guide/cn/elasticsearch/guide/current/function-score-query.html


獲取最新文章夺饲,可關(guān)注博客地址:https://jenkinwang.github.io/戳吝,或掃碼關(guān)注微信公眾號:一只慵懶的程序猿

一只慵懶的程序猿.jpg

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末太防,一起剝皮案震驚了整個濱河市盈包,隨后出現(xiàn)的幾起案子寓娩,更是在濱河造成了極大的恐慌寞埠,老刑警劉巖阱穗,帶你破解...
    沈念sama閱讀 222,000評論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件炊苫,死亡現(xiàn)場離奇詭異倦淀,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)科展,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,745評論 3 399
  • 文/潘曉璐 我一進(jìn)店門糠雨,熙熙樓的掌柜王于貴愁眉苦臉地迎上來垮庐,“玉大人寒亥,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 168,561評論 0 360
  • 文/不壞的土叔 我叫張陵吆玖,是天一觀的道長翅阵。 經(jīng)常有香客問我讹语,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 59,782評論 1 298
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘睁壁。我一直安慰自己,他們只是感情好遂填,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,798評論 6 397
  • 文/花漫 我一把揭開白布漏麦。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪眉尸。 梳的紋絲不亂的頭發(fā)上陈莽,一...
    開封第一講書人閱讀 52,394評論 1 310
  • 那天迅细,我揣著相機(jī)與錄音统阿,去河邊找鬼。 笑死们妥,一個胖子當(dāng)著我的面吹牛监婶,可吹牛的內(nèi)容都是我干的带污。 我是一名探鬼主播刮刑,決...
    沈念sama閱讀 40,952評論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼宇立!你這毒婦竟也來了柳琢?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,852評論 0 276
  • 序言:老撾萬榮一對情侶失蹤活逆,失蹤者是張志新(化名)和其女友劉穎精刷,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體蔗候,經(jīng)...
    沈念sama閱讀 46,409評論 1 318
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡怒允,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,483評論 3 341
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了锈遥。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片纫事。...
    茶點(diǎn)故事閱讀 40,615評論 1 352
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖所灸,靈堂內(nèi)的尸體忽然破棺而出丽惶,到底是詐尸還是另有隱情,我是刑警寧澤爬立,帶...
    沈念sama閱讀 36,303評論 5 350
  • 正文 年R本政府宣布钾唬,位于F島的核電站,受9級特大地震影響侠驯,放射性物質(zhì)發(fā)生泄漏抡秆。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,979評論 3 334
  • 文/蒙蒙 一吟策、第九天 我趴在偏房一處隱蔽的房頂上張望儒士。 院中可真熱鬧,春花似錦檩坚、人聲如沸着撩。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,470評論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至权谁,卻和暖如春剩檀,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背旺芽。 一陣腳步聲響...
    開封第一講書人閱讀 33,571評論 1 272
  • 我被黑心中介騙來泰國打工沪猴, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留辐啄,地道東北人。 一個月前我還...
    沈念sama閱讀 49,041評論 3 377
  • 正文 我出身青樓运嗜,卻偏偏與公主長得像壶辜,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子担租,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,630評論 2 359