查询重打分 #
查询重打分(Rescore)允许你在初始查询返回 Top-N 结果后,用更复杂、更精细的查询对这些结果重新打分。这是一种二阶段打分策略:第一阶段用快速查询(如 match)粗筛,第二阶段用代价更高的查询(如 match_phrase、function_score)精排。
使用场景 #
- 短语精排:先用
match召回,再用match_phrase提升短语完全匹配的文档 - 复杂评分:初始召回后,对 Top 结果做
function_score或script_score精细计算 - 向量混排:用 BM25 召回后,对 Top-N 用 kNN 重打分
基础用法 #
GET shakespeare/_search
{
"query": {
"match": {
"text_entry": "to be or not to be"
}
},
"rescore": {
"window_size": 100,
"query": {
"rescore_query": {
"match_phrase": {
"text_entry": {
"query": "to be or not to be",
"slop": 2
}
}
},
"query_weight": 0.7,
"rescore_query_weight": 1.2
}
}
}
参数说明 #
顶层参数 #
| 参数 | 类型 | 默认值 | 说明 |
|---|---|---|---|
window_size | Integer | 10 | 每个分片上参与重打分的 Top-N 文档数 |
query | Object | 必填 | 重打分查询配置 |
query 对象参数 #
| 参数 | 类型 | 默认值 | 说明 |
|---|---|---|---|
rescore_query | Query DSL | 必填 | 用于重打分的查询(任意 Query DSL) |
query_weight | Float | 1.0 | 原始查询分数的权重 |
rescore_query_weight | Float | 1.0 | 重打分查询分数的权重 |
score_mode | String | total | 原始分数与重打分分数的合并方式 |
score_mode 可选值 #
| 值 | 公式 | 说明 |
|---|---|---|
total(或 sum) | $\text{original} \times w_1 + \text{rescore} \times w_2$ | 加权求和(默认) |
avg | $\frac{\text{original} \times w_1 + \text{rescore} \times w_2}{2}$ | 加权平均 |
max | $\max(\text{original} \times w_1,\ \text{rescore} \times w_2)$ | 取最大值 |
min | $\min(\text{original} \times w_1,\ \text{rescore} \times w_2)$ | 取最小值 |
multiply(或 product) | $\text{original} \times w_1 \times \text{rescore} \times w_2$ | 加权乘积 |
多级重打分 #
可以指定多个 rescore 对象组成数组,按顺序依次执行:
GET shakespeare/_search
{
"query": {
"match": {
"text_entry": "love"
}
},
"rescore": [
{
"window_size": 200,
"query": {
"rescore_query": {
"match_phrase": {
"text_entry": {
"query": "love",
"slop": 1
}
}
},
"query_weight": 0.7,
"rescore_query_weight": 1.5
}
},
{
"window_size": 50,
"query": {
"rescore_query": {
"function_score": {
"script_score": {
"script": "_score * doc['popularity'].value"
}
}
},
"score_mode": "multiply"
}
}
]
}
每一级重打分都在上一级的结果基础上执行。
性能建议 #
window_size越大,精度越高但开销越大。建议从 100~500 开始调试- 重打分查询不影响召回率(只影响已召回文档的排序)
- 重打分不支持与
sort一起使用(需要按_score排序才有意义) - 每个分片独立执行重打分,因此实际重打分文档数 =
window_size × 分片数