Elasticsearch Script Score查询深度解析
elasticsearch 项目地址: https://gitcode.com/gh_mirrors/elas/elasticsearch
什么是Script Score查询
Script Score查询是Elasticsearch提供的一种高级查询功能,它允许开发者使用自定义脚本对查询结果进行评分计算。这种查询方式特别适用于需要基于复杂业务逻辑进行文档排序的场景。
核心概念
基本结构
一个Script Score查询包含两个主要部分:
- 基础查询(query):用于筛选文档集
- 评分脚本(script):对筛选出的文档进行自定义评分
{
"query": {
"script_score": {
"query": { /* 基础查询 */ },
"script": { /* 评分脚本 */ }
}
}
}
评分限制
需要注意的是,Script Score查询的最终评分必须是非负数(≥0),这是Lucene底层的限制要求。
实际应用示例
简单数值计算
假设我们有一个包含"my-int"字段的文档集,我们可以这样计算评分:
GET /_search
{
"query": {
"script_score": {
"query": {"match": {"message": "elasticsearch"}},
"script": {
"source": "doc['my-int'].value / 10"
}
}
}
}
这个例子中,每个文档的评分是其"my-int"字段值除以10的结果。
高级参数详解
核心参数
- query(必需):基础查询对象
- script(必需):评分脚本对象
- min_score(可选):过滤低于此评分的文档
- boost(可选):评分倍增系数,默认为1.0
脚本中访问评分
在脚本中,可以通过_score
变量访问文档的基础相关性评分:
"source": "_score * doc['boost'].value"
内置评分函数
Elasticsearch提供了一系列预定义的评分函数,建议优先使用这些函数而非自定义实现,因为它们经过了性能优化。
1. 饱和函数(Saturation)
公式:value/(k + value)
"script": {
"source": "saturation(doc['my-int'].value, 1)"
}
2. Sigmoid函数
公式:value^a/(k^a + value^a)
"script": {
"source": "sigmoid(doc['my-int'].value, 2, 1)"
}
3. 随机评分函数
生成0到1之间的随机评分:
"script": {
"source": "randomScore(100, '_seq_no')"
}
注意:如果不指定字段名,将使用Lucene内部文档ID作为随机源,但这种方式在文档合并后可能不可重现。
4. 衰减函数
适用于数值、地理位置和日期字段,提供三种衰减模式:
- 线性衰减(Linear)
- 指数衰减(Exp)
- 高斯衰减(Gauss)
数值衰减示例
"script": {
"source": "decayNumericLinear(params.origin, params.scale, params.offset, params.decay, doc['dval'].value)",
"params": {
"origin": 20,
"scale": 10,
"decay": 0.5,
"offset": 0
}
}
地理位置衰减示例
"script": {
"source": "decayGeoExp(params.origin, params.scale, params.offset, params.decay, doc['location'].value)",
"params": {
"origin": "40, -70.12",
"scale": "200km",
"offset": "0km",
"decay": 0.2
}
}
日期衰减示例
"script": {
"source": "decayDateGauss(params.origin, params.scale, params.offset, params.decay, doc['date'].value)",
"params": {
"origin": "2008-01-01T01:00:00Z",
"scale": "1h",
"offset": "0",
"decay": 0.5
}
}
注意:日期衰减函数不支持"now"计算,且仅限于默认格式和时区。
性能优化建议
- 使用参数化脚本:通过
params
传递变量,避免脚本重新编译 - 考虑替代方案:对于简单场景,使用
rank_feature
或distance_feature
查询可能更高效 - 避免昂贵查询:当
search.allow_expensive_queries
设为false时,Script Score查询不会执行
从Function Score迁移
Script Score查询是Function Score查询的简化替代方案。以下是常见迁移模式:
权重(weight)实现
"script": {
"source": "params.weight * _score",
"params": {"weight": 2}
}
字段值因子(field_value_factor)实现
"script": {
"source": "Math.log10(doc['field'].value * params.factor)",
"params": {"factor": 5}
}
处理缺失字段:
"script": {
"source": "Math.log10((doc['field'].size() == 0 ? 1 : doc['field'].value()) * params.factor)",
"params": {"factor": 5}
}
调试技巧
可以通过Explain API查看评分计算详情:
GET /my-index/_explain/0
{
"query": {
"script_score": {
"query": {"match": {"message": "elasticsearch"}},
"script": {
"source": """
long count = doc['count'].value;
double normalizedCount = count / 10;
if (explanation != null) {
explanation.set('normalized count = count / 10 = ' + count + ' / 10 = ' + normalizedCount);
}
return normalizedCount;
"""
}
}
}
}
最佳实践:始终检查explanation
是否为null,因为普通搜索请求中它不可用。
总结
Script Score查询为Elasticsearch提供了强大的自定义评分能力,特别适合需要复杂业务逻辑排序的场景。通过合理使用内置函数和性能优化技巧,可以在满足业务需求的同时保持良好的查询性能。
elasticsearch 项目地址: https://gitcode.com/gh_mirrors/elas/elasticsearch
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考