一、概要
Elasticsearch 的评分机制(Relevance Scoring)是其全文搜索能力的核心,它决定了文档与查询的匹配程度并按相关性排序返回结果。
二、评分机制基础
-
基本概念
- 目的:
- 相关性排序(Relevance Ranking)
- 将匹配文档按照与查询的相关性从高到低排序。
- 确保最相关的文档出现在结果列表顶部。
- 示例:搜索"智能手机"时,标题完全匹配的产品排在描述部分匹配的产品之前。
- 搜索质量优化
- 区分"勉强匹配"和"精确匹配"的文档。
- 识别文档中真正重要的匹配内容。
- 示例:匹配稀有词项的文档比匹配常见词项的文档得分更高。
- 相关性排序(Relevance Ranking)
- 特点:
- 无固定上限,分数越高相关性越强。
- 不同查询类型的评分计算方式不同。
- 任何搜索请求都会默认返回每个文档的评分,记录在响应的 _score 字段。
- 可通过 explain API 查看详细评分过程。
- 目的:
-
详细评分分析
- 使用 explain API 查看单个文档的详细评分计算过程:
响应包含详细解释:GET /your_index/_explain/1 {"query": {"match": {"title": "Elasticsearch"}} }
{"_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 参数,为搜索结果中的所有文档返回评分解释:
GET /your_index/_search {"explain": true, "query": {"match": {"title": "Elasticsearch"}} }
- 使用 Profile API 分析查询执行的详细时间信息和评分计算:
响应包含详细的性能分析:GET /your_index/_search {"profile": true,"query": {"match": {"title": "Elasticsearch"}} }
{"profile": {"shards": [{"searches": [{"query": [{"type": "MatchQuery","description": "title:elasticsearch","time_in_nanos": 125000,"breakdown": {...},"children": [...]}],"rewrite_time": 42000,"collector": [...]}]}]} }
- 使用 explain API 查看单个文档的详细评分计算过程:
三、基础评分模型
-
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
- TF (Term Frequency):词项在文档中出现的频率
-
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=完全归一化。
- k1:控制词频饱和度的参数(默认1.2)。
- 成为默认算法
-
BM25 优势
- 对短字段匹配更友好。
- 词频饱和更快(避免高频词主导结果)。
- 更符合现代信息检索需求。
四、评分组件深度解析
-
查询时评分因素
因素 描述 影响方式 词项权重 查询词项的重要性 可通过boost调整 协调因子 匹配查询条件的比例 匹配越多分数越高 查询归一化 复杂查询的平衡处理 长查询的分数调节 -
索引时评分因素
因素 存储位置 作用 文档频率 倒排索引 计算IDF 字段长度 norms 长度归一化 索引选项 index_options 控制存储信息量
五、影响评分的核心因素
-
TF-IDF(词频-逆文档频率)
- 词频(Term Frequency, TF):查询词在文档中出现的次数越多,得分越高。
- 逆文档频率(Inverse Document Frequency, IDF):查询词在所有文档中出现的频率越低(越稀有),得分越高。
-
字段长度归一化(Field-length Norm)
- 较短的字段中匹配到的词比长字段中匹配到的词权重更高。
- 例如:标题匹配比正文匹配得分更高。
-
查询提升(Boosting)
- 可以手动提升某些字段或查询条件的权重。
- 例如:
{"query": {"multi_match": {"query": "搜索词","fields": ["title^3", "content"] // title字段权重是content的3倍}} }
-
协调因子(Coordination Factor)
- 考虑文档中匹配到的查询条件数量。
- 匹配到的条件越多,得分越高
-
文档权重(Document Boosting)
- 单个文档可以设置权重提升值。
- 在索引时通过_boost参数设置。
-
其他因素
- 索引时的norms设置(是否考虑字段长度)。
- index_options设置(存储哪些信息用于评分)。
- 查询时的tie_breaker参数(处理多条件查询)。
- 查询时使用的分析器(影响分词结果)。
六、自定义评分
Elasticsearch 提供了多种方式来实现自定义评分,使您能够超越默认的相关性算法,根据业务需求定制搜索结果的排序。以下是主要的自定义评分方法:
- Function Score Query
最强大的自定义评分工具,允许修改原始_score或完全替换它:{"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}} }
- 脚本评分 (Script Score)
使用Painless脚本实现完全自定义的评分逻辑:{"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}}}} }
- 字段值因子 (Field Value Factor)
使用文档中的字段值来调整评分:{"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"}} }
- 衰减函数 (Decay Functions)
基于距离或时间的衰减评分:{"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"}} }
- 自定义相似度算法
在索引映射中定义自定义相似度:{"settings": {"index": {"similarity": {"custom_similarity": {"type": "BM25","b": 0.75,"k1": 1.2}}}},"mappings": {"properties": {"title": {"type": "text","similarity": "custom_similarity"}}} }
- 查询时提升 (Query-Time Boosting)
{"query": {"bool": {"should": [{ "match": { "title": { "query": "elasticsearch", "boost": 3 } } },{ "match": { "content": { "query": "elasticsearch", "boost": 1 } } }]}} }
七、固定评分
constant_score 是 Elasticsearch 中一种特殊的查询类型,它允许你为过滤条件分配一个固定的评分,而不是由 Elasticsearch 计算相关性评分。这在某些场景下非常有用,特别是当你只关心文档是否匹配而不需要相关性评分时。
- 基本语法
{"query": {"constant_score": {"filter": {// 你的过滤条件},"boost": 1.0 // 可选,默认值为1.0}} }
- 核心特点
- 固定评分:所有匹配的文档都会获得相同的评分。
- 性能优势:跳过了评分计算阶段,提高查询效率。
- 只包含 filter 上下文:不支持 query 上下文的条件。
- 典型使用场景
- 精确匹配过滤(不关心评分)
{"query": {"constant_score": {"filter": {"term": { "status": "published" }}}} }
- 范围过滤
{"query": {"constant_score": {"filter": {"range": { "price": { "gte": 100, "lte": 500 } }},"boost": 1.5}} }
- 组合多个过滤条件
{"query": {"constant_score": {"filter": {"bool": {"must": [{ "term": { "category": "electronics" } },{ "range": { "stock": { "gt": 0 } } }]}}}} }
- 调整 boost 值控制结果排序
{"query": {"bool": {"should": [{"constant_score": {"filter": { "term": { "priority": "high" } },"boost": 3.0}},{"constant_score": {"filter": { "term": { "priority": "medium" } },"boost": 2.0}}]}} }
- 精确匹配过滤(不关心评分)
八、优化评分策略
优化 Elasticsearch 评分策略是提高搜索结果相关性的关键。以下是系统化的优化方法和实践建议:
8.1 基础评分模型优化
- 选择合适的相似度算法
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"}}} }
- 字段级别优化
- 重要字段提升:
{"query": {"multi_match": {"query": "搜索词","fields": ["title^3", "description^2", "content"]}} }
- 禁用不必要字段的评分:
{"mappings": {"properties": {"metadata": {"type": "text","norms": false // 禁用长度归一化}}} }
- 重要字段提升:
8.2 业务导向的评分优化
- 业务权重集成
{"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"}} }
- 时间衰减策略
{"query": {"function_score": {"query": { "match_all": {} },"functions": [{"exp": {"publish_date": {"origin": "now","scale": "30d","offset": "7d","decay": 0.5}}}],"score_mode": "multiply"}} }
8.3 高级优化技术
- 个性化评分
{"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": ["苹果", "华为"]}}}}]}} }