大多數(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
卷哩。 -
modifier
:none
,log
,log1p
,log2p
,ln
,ln1p
,ln2p
,square
,sqrt
,reciprocal
捌年。默認(rèn)值是none
.
-
-
decay_functions
:衰減函數(shù)的功能與范圍查詢類似,但它具有更平滑的邊緣褒颈。衰減函數(shù)支持gauss
、linear
、exp
中任意一種函數(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ù)的衰減曲線形狀:
以上就是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)注微信公眾號:一只慵懶的程序猿
。