脚本评分查询
使用 script_score
查询可以通过脚本自定义评分计算。对于昂贵的评分函数,您可以使用 script_score
查询仅为已过滤的返回文档计算评分。
示例
例如,以下请求创建一个包含一个文档的索引
PUT testindex1/_doc/1
{
"name": "John Doe",
"multiplier": 0.5
}
您可以使用 match
查询返回 name
字段中包含 John
的所有文档
GET testindex1/_search
{
"query": {
"match": {
"name": "John"
}
}
}
在响应中,文档 1 的评分为 0.2876821
{
"took": 7,
"timed_out": false,
"_shards": {
"total": 1,
"successful": 1,
"skipped": 0,
"failed": 0
},
"hits": {
"total": {
"value": 1,
"relation": "eq"
},
"max_score": 0.2876821,
"hits": [
{
"_index": "testindex1",
"_id": "1",
"_score": 0.2876821,
"_source": {
"name": "John Doe",
"multiplier": 0.5
}
}
]
}
}
现在,让我们通过一个脚本来改变文档评分,该脚本将 _score
字段的值乘以 multiplier
字段的值作为评分。在以下查询中,您可以在 _score
变量中访问文档的当前相关性评分,并将 multiplier
值作为 doc['multiplier'].value
访问
GET testindex1/_search
{
"query": {
"script_score": {
"query": {
"match": {
"name": "John"
}
},
"script": {
"source": "_score * doc['multiplier'].value"
}
}
}
}
在响应中,文档 1 的评分是原始评分的一半
{
"took": 8,
"timed_out": false,
"_shards": {
"total": 1,
"successful": 1,
"skipped": 0,
"failed": 0
},
"hits": {
"total": {
"value": 1,
"relation": "eq"
},
"max_score": 0.14384104,
"hits": [
{
"_index": "testindex1",
"_id": "1",
"_score": 0.14384104,
"_source": {
"name": "John Doe",
"multiplier": 0.5
}
}
]
}
}
参数
script_score
查询支持以下顶级参数。
参数 | 数据类型 | 描述 |
---|---|---|
query(查询) | 对象 | 用于搜索的查询。必需。 |
script(脚本) | 对象 | 用于计算由 query 返回的文档评分的脚本。必需。 |
min_score(最小评分) | 浮点型 | 从结果中排除评分低于 min_score 的文档。可选。 |
提升 | 浮点型 | 通过给定的乘数提高文档的评分。小于 1.0 的值会降低相关性,大于 1.0 的值会提高相关性。默认值为 1.0。 |
script_score
查询计算的相关性评分不能为负值。
使用内置函数自定义评分计算
要自定义评分计算,您可以使用内置的 Painless 函数之一。对于每个函数,OpenSearch 都提供一个或多个 Painless 方法,您可以在脚本评分上下文中访问它们。您可以直接调用以下部分中列出的 Painless 方法,而无需使用类名或实例名限定符。
饱和函数
饱和函数将饱和度计算为 score = value /(value + pivot)
,其中 value
是字段值,pivot
的选择使得如果 value
大于 pivot
,则评分大于 0.5;如果 value
小于 pivot
,则评分小于 0.5。评分范围在 (0, 1) 之间。要应用饱和函数,请调用以下 Painless 方法
double saturation(double <field-value>, double <pivot>)
示例
以下示例查询在 articles
索引中搜索文本 neural search
。它将原始文档相关性评分与首先通过饱和函数转换的 article_rank
值结合起来
GET articles/_search
{
"query": {
"script_score": {
"query": {
"match": { "article_name": "neural search" }
},
"script" : {
"source" : "_score + saturation(doc['article_rank'].value, 11)"
}
}
}
}
Sigmoid 函数
与饱和函数类似,sigmoid 函数将评分计算为 score = value^exp/ (value^exp + pivot^exp)
,其中 value
是字段值,exp
是一个指数缩放因子,pivot
的选择使得如果 value
大于 pivot
,则评分大于 0.5;如果 value
小于 pivot
,则评分小于 0.5。要应用 sigmoid 函数,请调用以下 Painless 方法
double sigmoid(double <field-value>, double <pivot>, double <exp>)
示例
以下示例查询在 articles
索引中搜索文本 neural search
。它将原始文档相关性评分与首先通过 sigmoid 函数转换的 article_rank
值结合起来
GET articles/_search
{
"query": {
"script_score": {
"query": {
"match": { "article_name": "neural search" }
},
"script" : {
"source" : "_score + sigmoid(doc['article_rank'].value, 11, 2)"
}
}
}
}
随机评分
随机评分函数生成 [0, 1) 范围内的均匀分布随机评分。要了解该函数的工作原理,请参阅随机评分函数。要应用随机评分函数,请调用以下 Painless 方法之一
double randomScore(int <seed>)
: 使用内部 Lucene 文档 ID 作为种子值。double randomScore(int <seed>, String <field-name>)
示例
以下查询使用带 seed
和 field
的 random_score
函数
GET articles/_search
{
"query": {
"script_score": {
"query": {
"match": { "article_name": "neural search" }
},
"script" : {
"source" : "randomScore(20, '_seq_no')"
}
}
}
}
衰减函数
使用衰减函数,您可以根据邻近度或新近度对结果进行评分。要了解更多信息,请参阅衰减函数。您可以使用指数、高斯或线性衰减曲线计算评分。要应用衰减函数,请根据字段类型调用以下 Painless 方法之一
- 数值字段
double decayNumericGauss(double <origin>, double <scale>, double <offset>, double <decay>, double <field-value>)
double decayNumericExp(double <origin>, double <scale>, double <offset>, double <decay>, double <field-value>)
double decayNumericLinear(double <origin>, double <scale>, double <offset>, double <decay>, double <field-value>)
- 地理点字段
double decayGeoGauss(String <origin>, String <scale>, String <offset>, double <decay>, GeoPoint <field-value>)
double decayGeoExp(String <origin>, String <scale>, String <offset>, double <decay>, GeoPoint <field-value>)
double decayGeoLinear(String <origin>, String <scale>, String <offset>, double <decay>, GeoPoint <field-value>)
- 日期字段
double decayDateGauss(String <origin>, String <scale>, String <offset>, double <decay>, JodaCompatibleZonedDateTime <field-value>)
double decayDateExp(String <origin>, String <scale>, String <offset>, double <decay>, JodaCompatibleZonedDateTime <field-value>)
double decayDateLinear(String <origin>, String <scale>, String <offset>, double <decay>, JodaCompatibleZonedDateTime <field-value>)
示例:数值字段
以下查询对数值字段使用指数衰减函数
GET articles/_search
{
"query": {
"script_score": {
"query": {
"match": {
"article_name": "neural search"
}
},
"script": {
"source": "decayNumericExp(params.origin, params.scale, params.offset, params.decay, doc['article_rank'].value)",
"params": {
"origin": 50,
"scale": 20,
"offset": 30,
"decay": 0.5
}
}
}
}
}
示例:地理点字段
以下查询对地理点字段使用高斯衰减函数
GET hotels/_search
{
"query": {
"script_score": {
"query": {
"match": {
"name": "hotel"
}
},
"script": {
"source": "decayGeoGauss(params.origin, params.scale, params.offset, params.decay, doc['location'].value)",
"params": {
"origin": "40.71,74.00",
"scale": "300ft",
"offset": "200ft",
"decay": 0.25
}
}
}
}
}
示例:日期字段
以下查询对日期字段使用线性衰减函数
GET blogs/_search
{
"query": {
"script_score": {
"query": {
"match": {
"name": "opensearch"
}
},
"script": {
"source": "decayDateLinear(params.origin, params.scale, params.offset, params.decay, doc['date_posted'].value)",
"params": {
"origin": "2022-04-24",
"scale": "6d",
"offset": "1d",
"decay": 0.25
}
}
}
}
}
词频函数
词频函数在评分脚本源中公开词元级统计信息。您可以使用这些统计信息来实现自定义信息检索和排名算法,例如按流行度进行查询时乘性或加性评分提升。要应用词频函数,请调用以下 Painless 方法之一
int termFreq(String <field-name>, String <term>)
: 检索特定词元在字段中的词频。long totalTermFreq(String <field-name>, String <term>)
: 检索特定词元在字段中的总词频。long sumTotalTermFreq(String <field-name>)
: 检索字段中所有词元总词频的和。
示例
以下查询将 fields
列表中每个字段的总词频乘以 multiplier
值作为评分。
GET /demo_index_v1/_search
{
"query": {
"function_score": {
"query": {
"match_all": {}
},
"script_score": {
"script": {
"source": """
for (int x = 0; x < params.fields.length; x++) {
String field = params.fields[x];
if (field != null) {
return params.multiplier * totalTermFreq(field, params.term);
}
}
return params.default_value;
""",
"params": {
"fields": ["title", "description"],
"term": "ai",
"multiplier": 2,
"default_value": 1
}
}
}
}
}
}
如果 search.allow_expensive_queries
设置为 false
,则 script_score
查询将不会执行。