Elasticsearch 评分机制

一、概要

Elasticsearch 的评分机制(Relevance Scoring)是其全文搜索能力的核心,它决定了文档与查询的匹配程度并按相关性排序返回结果。

二、评分机制基础

  1. 基本概念

    • 目的:
      1. 相关性排序(Relevance Ranking)
        • 将匹配文档按照与查询的相关性从高到低排序。
        • 确保最相关的文档出现在结果列表顶部。
        • 示例:搜索"智能手机"时,标题完全匹配的产品排在描述部分匹配的产品之前。
      2. 搜索质量优化
        • 区分"勉强匹配"和"精确匹配"的文档。
        • 识别文档中真正重要的匹配内容。
        • 示例:匹配稀有词项的文档比匹配常见词项的文档得分更高。
    • 特点:
      • 无固定上限,分数越高相关性越强。
      • 不同查询类型的评分计算方式不同。
      • 任何搜索请求都会默认返回每个文档的评分,记录在响应的 _score 字段。
      • 可通过 explain API 查看详细评分过程。
  2. 详细评分分析

    • 使用 explain API 查看单个文档的详细评分计算过程:

      bash 复制代码
      GET /your_index/_explain/1
      {
        "query": {
          "match": {
            "title": "Elasticsearch"
          }
        }
      }

      响应包含详细解释:

      bash 复制代码
      {
        "_index": "your_index",
        "_id": "1",
        "matched": true,
        "explanation": {
          "value": 1.3862942,
          "description": "weight(title:elasticsearch in 0) [PerFieldSimilarity], result of:",
          "details": [
            {
              "value": 1.3862942,
              "description": "score(freq=1.0), computed as boost * idf * tf from:",
              "details": [
                {
                  "value": 2.2,
                  "description": "boost"
                },
                {
                  "value": 0.6931471,
                  "description": "idf, computed as log(1 + (N - n + 0.5) / (n + 0.5)) from:",
                  "details": [...]
                },
                {
                  "value": 0.90909094,
                  "description": "tf, computed as freq / (freq + k1 * (1 - b + b * dl / avgdl)) from:",
                  "details": [...]
                }
              ]
            }
          ]
        }
      }
    • 搜索时添加 explain 参数,为搜索结果中的所有文档返回评分解释:

      bash 复制代码
      GET /your_index/_search
      {
        "explain": true, 
        "query": {
          "match": {
            "title": "Elasticsearch"
          }
        }
      }
    • 使用 Profile API 分析查询执行的详细时间信息和评分计算:

      bash 复制代码
      GET /your_index/_search
      {
        "profile": true,
        "query": {
          "match": {
            "title": "Elasticsearch"
          }
        }
      }

      响应包含详细的性能分析:

      bash 复制代码
      {
        "profile": {
          "shards": [
            {
              "searches": [
                {
                  "query": [
                    {
                      "type": "MatchQuery",
                      "description": "title:elasticsearch",
                     "time_in_nanos": 125000,
                    "breakdown": {...},
                   "children": [...]
                  }
                 ],
                  "rewrite_time": 42000,
                "collector": [...]
               }
              ]
            }
          ]
        }
      }

三、基础评分模型

  1. TF-IDF 模型 (早期版本默认)

    • 计算公式:score(q,d) = queryNorm(q) × coord(q,d) × ∑ ( tf(t in d) × idf(t)² × t.getBoost() × norm(t,d) )
    • 核心组件:
      • TF (Term Frequency):词项在文档中出现的频率
        • 出现次数越多,得分越高。
        • 计算公式:tf(t in d) = √frequency
      • IDF (Inverse Document Frequency):词项在所有文档中的稀有程度
        • 越稀有的词项权重越高。
        • 计算公式:idf(t) = 1 + log(numDocs / (docFreq + 1))
      • Field-length Norm:字段长度归一化
        • 短字段匹配的权重更高。
        • 计算公式:norm(d) = 1 / √numTerms
  2. BM25 评分模型(Elasticsearch 5.x 及以后)

    • 成为默认算法
      • 从 Elasticsearch 5.x 开始,BM25 取代 TF-IDF 成为默认评分算法。
    • BM25 公式:score(D,Q) = ∑ IDF(qi) × (f(qi,D) × (k1 + 1)) / (f(qi,D) + k1 × (1 - b + b × |D| / avgdl))
    • 核心参数:
      • k1:控制词频饱和度的参数(默认1.2)。
        • 值越小饱和度越快。
      • b:控制字段长度影响的参数(默认0.75)
        • 0=禁用长度归一化,1=完全归一化。
  3. BM25 优势

    • 对短字段匹配更友好。
    • 词频饱和更快(避免高频词主导结果)。
    • 更符合现代信息检索需求。

四、评分组件深度解析

  1. 查询时评分因素

    因素 描述 影响方式
    词项权重 查询词项的重要性 可通过boost调整
    协调因子 匹配查询条件的比例 匹配越多分数越高
    查询归一化 复杂查询的平衡处理 长查询的分数调节
  2. 索引时评分因素

    因素 存储位置 作用
    文档频率 倒排索引 计算IDF
    字段长度 norms 长度归一化
    索引选项 index_options 控制存储信息量

五、影响评分的核心因素

  1. TF-IDF(词频-逆文档频率)

    • 词频(Term Frequency, TF):查询词在文档中出现的次数越多,得分越高。
    • 逆文档频率(Inverse Document Frequency, IDF):查询词在所有文档中出现的频率越低(越稀有),得分越高。
  2. 字段长度归一化(Field-length Norm)

    • 较短的字段中匹配到的词比长字段中匹配到的词权重更高。
    • 例如:标题匹配比正文匹配得分更高。
  3. 查询提升(Boosting)

    • 可以手动提升某些字段或查询条件的权重。

    • 例如:

      bash 复制代码
      {
        "query": {
          "multi_match": {
            "query": "搜索词",
            "fields": ["title^3", "content"]  // title字段权重是content的3倍
          }
        }
      }
  4. 协调因子(Coordination Factor)

    • 考虑文档中匹配到的查询条件数量。
    • 匹配到的条件越多,得分越高
  5. 文档权重(Document Boosting)

    • 单个文档可以设置权重提升值。
    • 在索引时通过_boost参数设置。
  6. 其他因素

    • 索引时的norms设置(是否考虑字段长度)。
    • index_options设置(存储哪些信息用于评分)。
    • 查询时的tie_breaker参数(处理多条件查询)。
    • 查询时使用的分析器(影响分词结果)。

六、自定义评分

Elasticsearch 提供了多种方式来实现自定义评分,使您能够超越默认的相关性算法,根据业务需求定制搜索结果的排序。以下是主要的自定义评分方法:

  1. Function Score Query
    最强大的自定义评分工具,允许修改原始_score或完全替换它:

    bash 复制代码
    {
      "query": {
        "function_score": {
          "query": { "match": { "title": "elasticsearch" } },
          "functions": [
            {
              "filter": { "term": { "tags": "popular" } },
              "weight": 2
            },
            {
              "script_score": {
                "script": {
                  "source": "Math.log(doc['views'].value + 1)"
                }
              }
            }
          ],
          "score_mode": "sum",  // 函数结果如何组合:sum, multiply, avg, max, min, first
          "boost_mode": "multiply"  // 如何与原始分数组合:multiply, replace, sum, avg, max, min
        }
      }
    }
  2. 脚本评分 (Script Score)
    使用Painless脚本实现完全自定义的评分逻辑:

    bash 复制代码
    {
      "query": {
        "script_score": {
          "query": { "match_all": {} },
          "script": {
            "source": """
              double score = 0;
              // 基于点赞数和收藏数计算评分
              score += doc['likes'].value * 0.3;
              score += doc['favorites'].value * 0.7;
              // 新内容加分
              long age = params.now - doc['publish_date'].value.toInstant().toEpochMilli();
              score *= Math.max(0.1, 2 - age / (1000*60*60*24*30.0));
              return score;
            """,
            "params": {
              "now": 1700000000000
            }
          }
        }
      }
    }
  3. 字段值因子 (Field Value Factor)
    使用文档中的字段值来调整评分:

    bash 复制代码
    {
      "query": {
        "function_score": {
          "query": { "match": { "content": "elasticsearch" } },
          "field_value_factor": {
            "field": "popularity",
            "factor": 1.2,
            "modifier": "log1p",  // none, log, log1p, log2p, ln, ln1p, ln2p, square, sqrt, reciprocal
            "missing": 1
          },
          "boost_mode": "multiply"
        }
      }
    }
  4. 衰减函数 (Decay Functions)
    基于距离或时间的衰减评分:

    bash 复制代码
    {
      "query": {
        "function_score": {
          "query": { "match": { "name": "hotel" } },
          "functions": [
            {
              "gauss": {
                "location": {
                  "origin": "40.715, -74.011",  // 中心点
                  "scale": "2km",               // 衰减距离
                  "offset": "500m",             // 不衰减的范围
                  "decay": 0.5                 // 衰减率
                }
              }
            },
            {
              "exp": {
                "publish_date": {
                  "origin": "now",
                  "scale": "30d",
                  "offset": "7d",
                  "decay": 0.5
                }
              }
            }
          ],
          "score_mode": "multiply"
        }
      }
    }
  5. 自定义相似度算法
    在索引映射中定义自定义相似度:

    bash 复制代码
    {
      "settings": {
        "index": {
          "similarity": {
            "custom_similarity": {
              "type": "BM25",
              "b": 0.75,
              "k1": 1.2
            }
          }
        }
      },
      "mappings": {
        "properties": {
          "title": {
            "type": "text",
            "similarity": "custom_similarity"
          }
        }
      }
    }
  6. 查询时提升 (Query-Time Boosting)

    bash 复制代码
    {
      "query": {
        "bool": {
          "should": [
            { "match": { "title": { "query": "elasticsearch", "boost": 3 } } },
            { "match": { "content": { "query": "elasticsearch", "boost": 1 } } }
          ]
        }
      }
    }

七、固定评分

constant_score 是 Elasticsearch 中一种特殊的查询类型,它允许你为过滤条件分配一个固定的评分,而不是由 Elasticsearch 计算相关性评分。这在某些场景下非常有用,特别是当你只关心文档是否匹配而不需要相关性评分时。

  1. 基本语法

    bash 复制代码
    {
      "query": {
        "constant_score": {
          "filter": {
            // 你的过滤条件
          },
          "boost": 1.0  // 可选,默认值为1.0
        }
      }
    }
  2. 核心特点

    • 固定评分:所有匹配的文档都会获得相同的评分。
    • 性能优势:跳过了评分计算阶段,提高查询效率。
    • 只包含 filter 上下文:不支持 query 上下文的条件。
  3. 典型使用场景

    1. 精确匹配过滤(不关心评分)

      bash 复制代码
      {
        "query": {
          "constant_score": {
            "filter": {
              "term": { "status": "published" }
            }
          }
        }
      }
    2. 范围过滤

      bash 复制代码
      {
        "query": {
          "constant_score": {
            "filter": {
              "range": { "price": { "gte": 100, "lte": 500 } }
            },
            "boost": 1.5
          }
        }
      }
    3. 组合多个过滤条件

      bash 复制代码
      {
        "query": {
          "constant_score": {
            "filter": {
              "bool": {
                "must": [
                  { "term": { "category": "electronics" } },
                  { "range": { "stock": { "gt": 0 } } }
                ]
              }
            }
          }
        }
      }
    4. 调整 boost 值控制结果排序

      bash 复制代码
      {
        "query": {
          "bool": {
            "should": [
              {
                "constant_score": {
                  "filter": { "term": { "priority": "high" } },
                  "boost": 3.0
              }
              },
             {
                "constant_score": {
                  "filter": { "term": { "priority": "medium" } },
                  "boost": 2.0
               }
             }
            ]
          }
        }
      }

八、优化评分策略

优化 Elasticsearch 评分策略是提高搜索结果相关性的关键。以下是系统化的优化方法和实践建议:

8.1 基础评分模型优化
  1. 选择合适的相似度算法

    bash 复制代码
    PUT /my_index
    {
      "settings": {
        "similarity": {
          "custom_bm25": {
            "type": "BM25",       // 默认且推荐算法
            "k1": 1.2,           // 控制词频饱和度(默认1.2)
            "b": 0.75            // 控制字段长度归一化程度(0-1)
          }
        }
      },
      "mappings": {
        "properties": {
          "content": {
            "type": "text",
            "similarity": "custom_bm25"
          }
        }
      }
    }
  2. 字段级别优化

    • 重要字段提升:

      bash 复制代码
      {
        "query": {
          "multi_match": {
            "query": "搜索词",
            "fields": ["title^3", "description^2", "content"]
          }
        }
      }
    • 禁用不必要字段的评分:

      bash 复制代码
      {
        "mappings": {
          "properties": {
            "metadata": {
              "type": "text",
              "norms": false  // 禁用长度归一化
            }
          }
        }
      }
8.2 业务导向的评分优化
  1. 业务权重集成

    bash 复制代码
    {
      "query": {
        "function_score": {
          "query": { "match": { "product": "手机" } },
          "functions": [
            {
              "field_value_factor": {
                "field": "sales_volume",
                "modifier": "log1p",
                "factor": 0.1
              }
            },
            {
              "field_value_factor": {
                "field": "user_rating",
                "modifier": "sqrt",
                "factor": 1.2
              }
            }
          ],
          "boost_mode": "sum"
        }
      }
    }
  2. 时间衰减策略

    bash 复制代码
    {
      "query": {
        "function_score": {
          "query": { "match_all": {} },
          "functions": [
            {
              "exp": {
                "publish_date": {
                  "origin": "now",
                 "scale": "30d",
                "offset": "7d",
                  "decay": 0.5
                }
              }
            }
          ],
          "score_mode": "multiply"
        }
      }
    }
8.3 高级优化技术
  1. 个性化评分

    bash 复制代码
    {
      "query": {
        "function_score": {
          "query": { "match": { "category": "电子产品" } },
          "functions": [
            {
              "script_score": {
                "script": {
               "source": """
     	           // 基于用户偏好调整评分
    	           double boost = 1.0;
     	           if(params.user_preferences.contains(doc['brand'].value)) {
       	           boost = 2.0;
    	            }
    	            return _score * boost;
       	          """,
                  "params": {
                    "user_preferences": ["苹果", "华为"]
                  }
                }
              }
            }
          ]
        }
      }
    }
相关推荐
遇码几秒前
单机快速部署开源、免费的分布式任务调度系统——DolphinScheduler
大数据·运维·分布式·开源·定时任务·dolphin·scheduler
一个天蝎座 白勺 程序猿1 小时前
大数据(4.2)Hive核心操作实战指南:表创建、数据加载与分区/分桶设计深度解析
大数据·hive·hadoop
计算机毕设定制辅导-无忧学长1 小时前
TDengine 核心概念与时序数据模型深度解析(一)
大数据·时序数据库·tdengine
TDengine (老段)1 小时前
TDengine 中的命名与边界
大数据·数据库·物联网·oracle·时序数据库·tdengine·iotdb
Acrelhuang3 小时前
8.3MW屋顶光伏+光储协同:上海汽车变速器低碳工厂的能源革命-安科瑞黄安南
大数据·数据库·人工智能·物联网·数据库开发
SelectDB5 小时前
拉卡拉 x Apache Doris:统一金融场景 OLAP 引擎,查询提速 15 倍,资源直降 52%
大数据·数据库·数据分析
合合技术团队5 小时前
实测对比|法国 AI 独角兽公司发布的“最强 OCR”,实测效果如何?
大数据·人工智能·图像识别
lilye667 小时前
程序化广告行业(39/89):广告投放的数据分析与优化秘籍
大数据·人工智能·数据分析
小小寂寞的城8 小时前
Ubuntu里安装Jenkins
ubuntu·ci/cd·docker·jenkins
IT成长日记8 小时前
Elasticsearch安全加固指南:启用登录认证与SSL加密
安全·elasticsearch·ssl