有時ES默認的評分規則並不能滿足需求,時長會有在old_source的基礎上根據某字段的值需要重新打分的需求場景,比如在相關度相差不大的情況下時間越進越靠前,或者評論數越多越靠前等等。此時需要重新打分。對此可以通過兩種方式法來處理:
1、在創建索引的時候提高文檔的權重,根據因素字段值來給文檔設置boost.這種方式在lucene之前有效,之后就無效了。不建議采用。
2、通過function_query來設置分數。
通過function_query來設置分數
線性提升
如在相關度相差不大的情況下,投票的數量越多排名越往前。可以采用簡單的線性方式來處理:
GET /blogposts/post/_search
{
"query": {
"function_score": {
"query": {
"multi_match": {
"query": "popularity",
"fields": [ "title", "content" ]
}
},
"field_value_factor": {
"field": "votes",
"modifier": "log1p",
"factor": 2
}
}
}
}
其中:
- field:表示影響權重的字段例子中是votes
- modifier:表示影響的規則
- 修飾語 modifier 的值可以為:
none (默認狀態)
log 、 log1p 、 log2p 、 ln 、 ln1p 、 ln2p 、 square 、 sqrt 以及 reciprocal。
facror:表示影響因子。
通過上面設置后整個打分變為:
new_score = old_score * log(1 + factor * number_of_votes)
factor 值大於 1 會提升效果, factor 值小於 1 會降低效果。
初次之外還可以設置boost_mode影響因子和old_source通過什么運算來得出新分值。
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
}
}
}
boost_mode
multiply評分 _score 與函數值的積(默認)
sum評分 _score 與函數值的和
min評分 _score 與函數值間的較小值
max評分 _score 與函數值間的較大值
replace函數值替代評分 _scoremax_boost設置最大的得分分值
無論 field_value_factor 函數的結果如何,最終結果都不會大於 1.5
引入模型函數來控制二次評分
上線是一種線性的影響關系,有時會有范圍性質、分數變化緩慢的需求場景,此時在使用上面的方案未免為使分數變化的不太圓滑,es提供了三種衰減函數(decay functions)來計算分數,讓我們有能力在兩個滑動標准如:地點和價格,時間等之間權衡。
linear、 exp 和 gauss (線性、指數和高斯函數),它們可以操作數值、時間以及經緯度地理坐標點這樣的字段。所有三個函數都能接受以下參數:
origin:中心點 或字段可能的最佳值,落在原點 origin 上的文檔評分 _score 為滿分 1.0 。
scale:衰減率,即一個文檔從原點origin下落時,評分_score 改變的速度.(例如,每 £10 歐元或每 100 米)
decay:從原點 origin 衰減到 scale 所得的評分 _score ,默認值為 0.5 。
offset:以原點 origin 為中心點,為其設置一個非零的偏移量 offset 覆蓋一個范圍,而不只是單個原點。在范圍 -offset <= origin <= +offset 內的所有評分 _score 都是 1.0 。
這三個函數的唯一區別就是它們衰減曲線的形狀,用圖來說明會更為直觀
圖 圖 33 “衰減函數曲線” 中所有曲線的原點 origin (即中心點)的值都是 40 , offset 是 5 ,也就是在范圍 40 - 5 <= value <= 40 + 5 內的所有值都會被當作原點 origin 處理——所有這些點的評分都是滿分 1.0 。
在此范圍之外,評分開始衰減,衰減率由 scale 值(此例中的值為 5 )和 衰減值 decay (此例中為默認值 0.5 )共同決定。結果是所有三個曲線在 origin +/- (offset + scale) 處的評分都是 0.5 ,即點 30和 50 處。
linear 、 exp 和 gauss (線性、指數和高斯)函數三者之間的區別在於范圍( origin +/- (offset + scale) )之外的曲線形狀:
linear 線性函數是條直線,一旦直線與橫軸 0 相交,所有其他值的評分都是 0.0 。
exp 指數函數是先劇烈衰減然后變緩。
gauss 高斯函數是鍾形的——它的衰減速率是先緩慢,然后變快,最后又放緩。
選擇曲線的依據完全由期望評分 _score 的衰減速率來決定,即距原點 origin 的值。
回到我們的例子:用戶希望租一個離倫敦市中心近( { "lat": 51.50, "lon": 0.12} )且每晚不超過 £100 英鎊的度假屋,而且與距離相比, 我們的用戶對價格更為敏感,這樣查詢可以寫成:
{
"query": {
"function_score": {
"functions": [
{
"gauss": {
"price": {
"origin": "0",
"scale": "20"
}
}
},
{
"gauss": {
"location": {
"origin": "11, 12",
"scale": "2km"
}
}
}
],
"query": {
"match": {
"properties": "balcony"
}
},
"score_mode": "multiply"
}
}
}
location 字段以地理坐標點 geo_point 映射。
price 字段是數值。
price 語句是 location 語句權重的兩倍。
location 語句可以簡單理解為:
以倫敦市中作為原點 origin 。
所有距原點 origin 2km 范圍內的位置的評分是 1.0 。
距中心 5km ( offset + scale )的位置的評分是 0.5 。
weight 參數可以被用來調整每個語句的貢獻度,權重 weight 的默認值是 1.0 。這個值會先與每個句子的評分相乘,然后再通過 score_mode 的設置方式合並。