閱讀本文需要先了解 function_score 的相關知識,請看 ElasticSearch - function_score 簡介
首先準備數據和索引,在ES插入三筆數據,其中 title 是 text 類型,like 是 integer 類型(代表點贊量)
{ "title": "ES 入門", "like": 2 }
{ "title": "ES 進階", "like": 5 }
{ "title": "ES 最高難度", "like": 10 }
先使用一般的 query,查看普通的查詢的評分會是如何
GET mytest/doc/_search
{
"query": {
"match": {
"title": "ES"
}
}
}
"hits": [
{
"_score": 0.2876821,
"_source": { "title": "ES 入門", "like": 2 }
},
{
"_score": 0.20309238,
"_source": { "title": "ES 進階", "like": 5 }
},
{
"_score": 0.16540512,
"_source": { "title": "ES 最高難度", "like": 10 }
}
]
使用 function_score 的 field_value_factor 改變 _score
,將 old_score 乘上 like 的值
本來 “ES 最高難度” 的 score 是0.16540512,經過 field_value_factor 的改變,乘上了那個文檔中的like值(10)之後,新的 score 變為 1.6540513
GET mytest/doc/_search
{
"query": {
"function_score": {
"query": {
"match": {
"title": "ES"
}
},
"field_value_factor": {
"field": "like"
}
}
}
}
"hits": [
{
"_score": 1.6540513, //原本是0.16540512
"_source": { "title": "ES 最高難度", "like": 10 }
},
{
"_score": 1.0154619, //原本是0.20309238
"_source": { "title": "ES 進階", "like": 5 }
},
{
"_score": 0.5753642, //原本是0.2876821
"_source": { "title": "ES 入門", "like": 2 }
}
]
加上 max_boost,限制 field_value_factor 的最大加強 score
可以看到 ES 入門的加強 score 是2,在 max_boost 限制裡,所以不受影響
而 ES 進階和 ES 最高難度的 field_value_factor 函數產生的加強 score 因為超過 max_boost 的限制,所以被設為 3
GET mytest/doc/_search
{
"query": {
"function_score": {
"query": {
"match": {
"title": "ES"
}
},
"field_value_factor": {
"field": "like"
},
"max_boost": 3
}
}
}
"hits": [
{
"_score": 0.6092771, //原本是0.20309238
"_source": { "title": "ES 進階", "like": 5 }
},
{
"_score": 0.5753642, //原本是0.2876821
"_source": { "title": "ES 入門", "like": 2 }
},
{
"_score": 0.49621537, //原本是0.16540512
"_source": { "title": "ES 最高難度", "like": 10 }
}
]
有時候線性的計算 new_score = old_score * like值
的效果並不是那麼好,field_value_factor 中還支持 modifier、factor 參數,可以改變 like 值對 old_score 的影響
modifier 參數支持的值
new_score = old_score * like值
new_score = old_score * log(1 + like值)
new_score = old_score * log(2 + like值)
new_score = old_score * ln(like值)
new_score = old_score * ln(1 + like值)
new_score = old_score * ln(2 + like值)
factor 參數
new_score = old_score * log(1 + factor * like值)
對剛剛的例子加上 modifier、factor
GET mytest/doc/_search
{
"query": {
"function_score": {
"query": {
"match": {
"title": "ES"
}
},
"field_value_factor": {
"field": "like",
"modifier": "log1p",
"factor": 2
}
}
}
}
就算加上了 modifier,但是 “全文評分 與 field_value_factor 函數值乘積” 的效果可能還是太大,我們可以通過參數 boost_mode
來決定 old_score 和 加強 score 合併的方法
如果將 boost_mode 改成 sum,可以大幅弱化最終效果,特別是使用一個較小的 factor 時
加入了 boost_mode = sum、且 factor = 0.1 的公式變為 new_score = old_score + log(1 + 0.1 * like值)
GET mytest/doc/_search
{
"query": {
"function_score": {
"query": {
"match": {
"title": "ES"
}
},
"field_value_factor": {
"field": "like",
"modifier": "log1p",
"factor": 0.1
},
"boost_mode": "sum"
}
}
}
另外使用 field_value_factor 時要注意,有的文檔可能會缺少這個字段的值,因此這時就要加上 missing
來給這些缺失字段值的文檔一個 default 的值
GET mytest/doc/_search
{
"query": {
"function_score": {
"query": {
"match": {
"title": "ES"
}
},
"field_value_factor": {
"field": "like",
"modifier": "log1p",
"factor": 0.1,
"missing": 1 //如果文檔沒有like值,就給他1的值讓他去做log1p的運算
},
"boost_mode": "sum"
}
}
}