Link Search Menu Expand Document Documentation Menu

脚本评分查询

使用 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>)

示例

以下查询使用带 seedfieldrandom_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 查询将不会执行。

剩余 350 字符

有问题?

想贡献?