ES相关度评分算法调优
场景:
现在我想把 相关度分数和 文章的浏览量关联起来, 浏览量越大,分数越高,怎么实现, 就要用自定义分数算法
自定义分数计算方式, 定义function score 指定字段直接参与到相关度分数计算中,甚至可以替换掉ES的相关度算分,自定义分数算法有几个关键点
上面讲了基本原理及参数,下面开始实战
POST /saytest/_bulk
{"index" : { "_id" : "1" }}
{"countnum" : 10, "say" : "hello world"}
{"index" : { "_id" : "2" }}
{"countnum" : 20, "say" : "hello java"}
{"index" : { "_id" : "3" }}
{"countnum" : 5, "say" : "hello spark learning"}
{"index" : { "_id" : "4" }}
{"countnum" : 15, "say" : "hello bye bye"}
{"index" : { "_id" : "5" }}
{"countnum" : 13, "say" : "hi world"}
查一下 如果不用 function_score 查询条件获取的基本分数 是多少
#不使用 function_score基本分数查询
GET /saytest/_search
{
"query": {
"match": {
"say": "java spark"
}
}
}

查询结果
| 文档 | 分数 | 分数 |
|---|---|---|
| id:2 | hello java | 1.4877305 |
| id:3 | java spark | 1.2576691 |
查询公式及参数如下:
GET /saytest/_search
{
"query": {
"function_score": {
"query": {
"match": {
"say": "java spark"
}
},
"field_value_factor": {
"field": "countnum",
"modifier": "log1p",
"factor": 1
},
"boost_mode": "multiply",
"max_boost": 2
}
}
}
自定义公式查询结果 :

这个分 如何算出来的 ? 我们来看一下原理
| 文档 | 分数 | 原分数 | 自定义分数 |
|---|---|---|---|
| id:2 | hello java | 1.4877305 | 1.967106 |
| id:3 | java spark | 1.2576691 | 0.978656 |
对于 id-2 文档doc,countnum=20, 计算方式 new_score = old_score * log(1+ factor*countnum)
也就是 1.4877305 * log ( 1+ 1 x 20) = 1.967105 ~ 就是 算出来的 1.967106
对于 id-3 文档doc, countnum = 5
也就是 1.2576691 * log (1+ 1 x 5) = 0.97865678273 ~ 同样也是 算出来的 0.978656

查询公式及参数如下:
GET /saytest/_search
{
"query": {
"function_score": {
"query": {
"match": {
"say": "java spark"
}
},
"field_value_factor": {
"field": "countnum",
"modifier": "ln",
"factor": 0.8
},
"boost_mode": "sum",
"max_boost": 10
}
}
}
自定义公式查询结果 :

这个分 如何算出来的 ? 我们来看一下原理
| 文档 | 分数 | 原分数 | 自定义分数 |
|---|---|---|---|
| id:2 | hello java | 1.4877305 | 3.4877305 |
| id:3 | java spark | 1.2576691 | 2.6439636 |
对于 id-2 文档doc,countnum=20, 计算方式new_score = old_score + ln( factor x countnum)
也就是 1.4877305 + ln ( 0.8 x 20) = 4.26031922224 ~ 就是 算出来的 4.260319,
对于 id-3 文档doc, countnum = 5
也就是 1.2576691 + ln(0.8 x 5) = 2.64396346112 ~ 同样也是 算出来的 2.6439636

上一步 我们看了一下 算分 原理, max_boost 其实是限制的 ln( factor x countnum) 分数, 我们修改下 max_boost 试试 效果,看看 是否能够限制 计算出来的分数
# max_boost 限制最大算出来的分=2
GET /saytest/_search
{
"query": {
"function_score": {
"query": {
"match": {
"say": "java spark"
}
},
"field_value_factor": {
"field": "countnum",
"modifier": "ln",
"factor": 0.8
},
"boost_mode": "sum",
"max_boost": 2
}
}
}

| 文档 | 分数 | 原分数 | 自定义分数 |
|---|---|---|---|
| id:2 | hello java | 1.4877305 | 3.4877305 |
| id:3 | java spark | 1.2576691 | 2.6439636 |
对于 id-2 文档doc,countnum=20, 计算方式new_score = old_score + ln( factor x countnum)
也就是 ln ( 0.8 x 20) = 2.77258872224 ,累加旧的分数 1.4877305 + 2.77258872224 = 4.26031922224 ~
为啥 id-2的分数是 3.4877305 呢?
再试一下,把max_boost调整为1 看下结果, 也是符合正确的

至此 我们已经学习了 ES Function score 自定义相关度分数算法的 实现逻辑, 并且可以根据自己的业务场景去定制算法了