自定义评分(Score Customization
)是指通过编程方式修改或覆盖 Elasticsearch 默认的相关度评分算法,以满足特定业务需求的过程。
Elasticsearch 默认使用 TF-IDF
(在较新版本中使用 BM25
)算法计算文档相关性,但有时业务需求需要特殊的排序逻辑。
建议先看一下我的这几篇博文:
- 【自然语言处理】文本表示:One-Hot、BOW、TF-IDF、N-Gram
- 【自然语言处理】BOW 和 TF-IDF 详解
- 【自然语言处理】文本相似度算法:TF-IDF 与 BM25
_score
)是 Elasticsearch 判断文档与查询匹配程度的量化值。match
、match_phrase
、multi_match
、query_string
term
(通常不评分,但可通过参数启用)、terms
、fuzzy
bool
(must
/ should
)、dis_max
、constant_score
boosting
、function_score
、script_score
boost
(可应用于任何查询)、tie_breaker
(在 dis_max
中使用)filter
和 must_not
被视为过滤器,不影响评分。其他查询子句会影响评分。
接下来,我们就介绍一下 boosting
、function_score
、script_score
这几个特殊查询是如何影响评分的。
{
"query": {
"function_score": {
"query": { "match": { "title": "手机" } },
"functions": [
{
"filter": { "term": { "brand": "苹果" } },
"weight": 2
},
{
"field_value_factor": {
"field": "sales",
"modifier": "log1p",
"factor": 0.1
}
},
{
"gauss": {
"date": {
"origin": "now",
"scale": "30d",
"offset": "7d",
"decay": 0.5
}
}
}
],
"score_mode": "sum",
"boost_mode": "multiply"
}
}
}
这段代码是一个 Elasticsearch 的 function_score
查询,用于对基础查询结果进行自定义评分调整。这是一个复合查询,主要包含:
match
查询)functions
数组)score_mode
和 boost_mode
)"query": { "match": { "title": "手机" } }
title
字段包含 “手机
” 的文档。_score
)。{
"filter": { "term": { "brand": "苹果" } },
"weight": 2
}
苹果
” 的文档应用权重。brand
字段精确匹配 “苹果
” 的文档。{
"field_value_factor": {
"field": "sales",
"modifier": "log1p",
"factor": 0.1
}
}
sales
字段)调整评分。field
:使用 sales
字段的值。modifier
:应用 log1p
函数(即 log(1 + sales)
),防止极高销量值对评分影响过大。factor
:乘以 0.1
的因子,减小影响程度。{
"gauss": {
"date": {
"origin": "now",
"scale": "30d",
"offset": "7d",
"decay": 0.5
}
}
}
date
)实现时间衰减评分。origin
:当前时间("now"
)作为基准点。scale
:衰减范围为 30 30 30 天。offset
: 7 7 7 天内不衰减,保持完整评分。decay
:衰减到 0.5 0.5 0.5(在 origin
+ offset
+ scale
时,得分为 0.5*原始分
)。"score_mode": "sum"
sum
表示将所有函数评分相加。multiply
(乘)、avg
(平均)、max
(最大)、min
(最小)、first
(第一个函数)。"boost_mode": "multiply"
multiply
表示将函数评分与原始 _score
相乘。replace
(替换)、sum
(相加)、avg
(平均)、max
(最大)、min
(最小)。这个查询会:
手机
” 的文档。苹果
品牌,评分 ×2
。取对数后
)增加评分。score_mode: sum
)。boost_mode: multiply
)。这种查询非常适合电商搜索场景,可以同时考虑关键词相关性、品牌偏好、销量热度和新品时效性。
{
"query": {
"boosting": {
"positive": { "match": { "title": "手机" } },
"negative": { "term": { "brand": "山寨" } },
"negative_boost": 0.2
}
}
}
这段代码使用了 Elasticsearch 的 boosting
查询,它是一种特殊的复合查询,用于对匹配某些条件的文档进行降权而非完全排除。下面我将详细解释每个部分的含义和作用:
positive
:正向查询(必须匹配)negative
:负向查询(匹配则降权)negative_boost
:降权系数"positive": { "match": { "title": "手机" } }
title
字段包含 “手机
” 的文档。negative
条件则保持原评分)。"negative": { "term": { "brand": "山寨" } }
term query
)。brand
字段精确等于 “山寨
” 的文档。negative
查询的文档不会被排除,而是会被降权。"negative_boost": 0.2
最终评分 = 原始评分 × 0.2
保持原始评分不变
positive
查询,找出所有标题包含 “手机
” 的文档。山寨
” 的文档。negative
条件的文档,将其评分乘以 0.2
。特性 |
|
must_not )
|
---|---|---|
匹配 negative 的文档 |
仍会返回,但评分降低 | 完全排除 |
适用场景 | 需要展示但降权低质量内容 | 需要完全排除某些内容 |
评分影响 | 可控的降权(通过 negative_boost ) |
完全不影响评分(只是过滤) |
negative_boost
必须是 0 0 0 到 1 1 1 之间的浮点数:
bool
+ must_not
)。可以组合多个 positive
和 negative
条件:
"positive": {
"bool": {
"should": [
{ "match": { "title": "手机" } },
{ "match": { "description": "智能" } }
]
}
},
"negative": {
"bool": {
"should": [
{ "term": { "brand": "山寨" } },
{ "range": { "price": { "lt": 100 } } }
]
}
}
bool
+ must_not
)消耗更多资源,因为要计算被降权文档的评分。bool
+ must_not
过滤。{
"query": {
"script_score": {
"query": { "match": { "title": "手机" } },
"script": {
"source": "_score * doc['popularity'].value * params.weight",
"params": { "weight": 1.5 }
}
}
}
}
match
查询,找出所有标题包含 “手机
” 的文档,并计算原始 _score
。popularity
字段的值。新评分 = _score × popularity × 1.5
。Term Frequency
)Inverse Document Frequency
)Field-length norm
)GET /products/_search
{
"explain": true,
"query": { "match": { "title": "手机" } }
}
k1
,b
)。bool
查询的 should
/ must
/ filter
。boost
值。自定义评分是 Elasticsearch 强大的功能之一,合理使用可以显著提升搜索体验,但也需要谨慎设计以避免性能问题和不可预期的排序结果。