【Elasticsearch】自定义评分检索

在这里插入图片描述

1.自定义评分

自定义评分Score Customization)是指通过编程方式修改或覆盖 Elasticsearch 默认的相关度评分算法,以满足特定业务需求的过程。

Elasticsearch 默认使用 TF-IDF(在较新版本中使用 BM25)算法计算文档相关性,但有时业务需求需要特殊的排序逻辑。

🚀 建议先看一下我的这几篇博文:

2.为什么需要自定义评分

  • 业务特定需求:默认评分可能无法准确反映业务领域的相关性标准。
  • 个性化排序:根据用户偏好、地理位置、时间敏感性等因素调整结果。
  • 商业逻辑:如提升付费内容、促销商品的排名。
  • 多维度排序:结合相关性、销量、评分、新鲜度等多个因素。
  • 领域专业知识:某些领域有独特的价值评估标准。

3.搜索结果相关度

  • 相关度_score)是 Elasticsearch 判断文档与查询匹配程度的量化值。
  • 自定义评分 不是替代相关度计算,而是在其基础上进行 调整或补充
  • 最终排序可以结合默认相关度和自定义评分因素。

4.影响相关度评分的查询子句

  • 全文检索查询matchmatch_phrasemulti_matchquery_string
  • 词项级别查询term(通常不评分,但可通过参数启用)、termsfuzzy
  • 复合查询boolmust / should)、dis_maxconstant_score
  • 特殊查询boostingfunction_scorescript_score
  • 查询参数boost(可应用于任何查询)、tie_breaker(在 dis_max 中使用)

filtermust_not 被视为过滤器,不影响评分。其他查询子句会影响评分。

5.控制相关度评分的方法

接下来,我们就介绍一下 boostingfunction_scorescript_score 这几个特殊查询是如何影响评分的。

5.1 Function Score Query

{
  "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_modeboost_mode

5.1.1 基础查询部分

"query": { "match": { "title": "手机" } }
  • 这是基础查询,查找 title 字段包含 “手机” 的文档。
  • 这部分会先执行,产生初始的相关性评分(_score)。

5.1.2 评分函数部分(functions 数组)

第一个函数:品牌加权
{
  "filter": { "term": { "brand": "苹果" } },
  "weight": 2
}
  • 作用:对品牌为 “苹果” 的文档应用权重。
  • 机制
    • 先过滤出 brand 字段精确匹配 “苹果” 的文档。
    • 为这些文档的评分乘以权重因子 2。
  • 效果:苹果品牌的产品会获得更高的排名。
第二个函数:销量因子
{
  "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*原始分)。
  • 效果:较新的文档会获得更高评分,但 7 7 7 天内无差别,之后逐渐衰减。

5.1.3 评分组合方式

score_mode
"score_mode": "sum"
  • 指定多个函数评分如何组合
  • sum 表示将所有函数评分相加。
  • 其他可选值:multiply)、avg平均)、max最大)、min最小)、first第一个函数)。
boost_mode
"boost_mode": "multiply"
  • 指定函数评分如何与原始查询评分组合
  • multiply 表示将函数评分与原始 _score 相乘。
  • 其他可选值:replace替换)、sum相加)、avg平均)、max最大)、min最小)。

5.1.4 整体效果

这个查询会:

  • 首先找出所有标题包含 “手机” 的文档。
  • 然后对这些文档进行评分调整:
    • 如果是 苹果 品牌,评分 ×2
    • 根据销量(取对数后)增加评分。
    • 根据时间远近衰减评分(越新评分越高)。
  • 将所有函数评分相加(score_mode: sum)。
  • 最后将总函数评分与原始评分相乘(boost_mode: multiply)。
  • 按最终评分排序返回结果。

这种查询非常适合电商搜索场景,可以同时考虑关键词相关性、品牌偏好、销量热度和新品时效性。

5.2 使用 Boosting Query

{
  "query": {
    "boosting": {
      "positive": { "match": { "title": "手机" } },
      "negative": { "term": { "brand": "山寨" } },
      "negative_boost": 0.2
    }
  }
}

这段代码使用了 Elasticsearch 的 boosting 查询,它是一种特殊的复合查询,用于对匹配某些条件的文档进行降权而非完全排除。下面我将详细解释每个部分的含义和作用:

  • positive:正向查询(必须匹配)
  • negative:负向查询(匹配则降权)
  • negative_boost:降权系数

5.2.1 正向查询(positive)

"positive": { "match": { "title": "手机" } }
  • 这是一个标准的全文匹配查询。
  • 会找出所有 title 字段包含 “手机” 的文档。
  • 这些文档都会被包含在最终结果中(如果不匹配 negative 条件则保持原评分)。

5.2.2 负向查询(negative)

"negative": { "term": { "brand": "山寨" } }
  • 这是一个精确匹配查询(term query)。
  • 会找出 brand 字段精确等于 “山寨” 的文档。
  • 匹配 negative 查询的文档不会被排除,而是会被降权

5.2.3 降权系数(negative_boost)

"negative_boost": 0.2
  • 这是一个介于 0 0 0 1 1 1 之间的乘数因子。
  • 对于 同时匹配 positive 和 negative 的文档:
    • 最终评分 = 原始评分 × 0.2
  • 对于 只匹配 positive 的文档:
    • 保持原始评分不变

5.3.4 工作流程

  • 首先执行 positive 查询,找出所有标题包含 “手机” 的文档。
  • 然后在这些文档中,找出品牌为 “山寨” 的文档。
  • 对匹配 negative 条件的文档,将其评分乘以 0.2
  • 最后按调整后的评分排序返回结果。

5.2.5 与 bool 查询的区别

特性
boosting 查询
bool 查询( must_not
匹配 negative 的文档仍会返回,但评分降低完全排除
适用场景需要展示但降权低质量内容需要完全排除某些内容
评分影响可控的降权(通过 negative_boost完全不影响评分(只是过滤)

5.2.6 典型应用场景

  • 降权低质量内容:如示例中的山寨品牌。
  • 处理过时内容:降权旧文章但不完全排除。
  • 广告混合排序:对广告内容适当降权。
  • 用户偏好处理:对用户不喜欢的类型降权。

5.2.7 参数注意事项

  • negative_boost 必须是 0 0 0 1 1 1 之间的浮点数:

    • 0.2 0.2 0.2 表示降权到原评分的 20 % 20\% 20%
    • 1.0 1.0 1.0 相当于没有效果。
    • 0.0 0.0 0.0 相当于完全排除(此时应使用 bool + must_not)。
  • 可以组合多个 positivenegative 条件:

    "positive": {
      "bool": {
        "should": [
          { "match": { "title": "手机" } },
          { "match": { "description": "智能" } }
        ]
      }
    },
    "negative": {
      "bool": {
        "should": [
          { "term": { "brand": "山寨" } },
          { "range": { "price": { "lt": 100 } } }
        ]
      }
    }
    

5.2.8 性能考虑

  • 比纯过滤(bool + must_not)消耗更多资源,因为要计算被降权文档的评分。
  • 对于需要完全排除的大量文档,建议使用 bool + must_not 过滤。
  • 适合处理少量需要降权而非完全排除的文档。

5.3 使用 Script Score

{
  "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
  • 按照计算出的新评分对文档进行排序。
  • 返回结果。

6.相关度评分控制技巧

  • 理解评分因素
    • 词频(Term Frequency
    • 逆文档频率(Inverse Document Frequency
    • 字段长度归一值(Field-length norm
  • 使用 Explain API 分析评分
    GET /products/_search
    {
      "explain": true,
      "query": { "match": { "title": "手机" } }
    }
    
  • 调整相似度算法
    • 可配置 BM25 参数(k1b)。
    • 或完全自定义相似度实现。
  • 查询结构调整
    • 合理使用 bool 查询的 should / must / filter
    • 调整不同子句的 boost 值。

自定义评分是 Elasticsearch 强大的功能之一,合理使用可以显著提升搜索体验,但也需要谨慎设计以避免性能问题和不可预期的排序结果。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

G皮T

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值