想象你是一家婚恋平台的资深红娘。一位用户提交了择偶要求:“希望对方爱旅行、会做饭、怕猫”。档案库里躺着几十万份资料,你必须在两三秒内把最可能合拍的人排在最前面——这正是搜索引擎在做的事。用户敲下一串查询词,搜索引擎从海量文档中挑出“最相关的”结果,而“最相关”不能靠人工翻档案,要靠一个可计算的数字:相关性评分。 早期的匹配只看“合不合格”,后来人们发现用户要的是“有多合适”的排序。于是诞生了 TF-IDF:看关键词在档案里出现几次、这个要求有多稀有;再进化到 BM25:承认同一句话说三遍就腻,长档案里的一笔带过不算数;最后还允许红娘开小灶,比如“同城加分”“学历加权”。这就是搜索引擎相关性评分从粗糙到精细的全过程。 这篇文章用红娘牵线的故事,带你搞懂 ES 默认的 BM25 打分原理,以及如何调优排序让用户更快找到目标。

岗位关联

掌握相关性评分原理,你就能在 Elasticsearch 搜索项目里读懂打分机制、精准调优排序,让用户更快找到目标——这是搜索与推荐工程师的核心功底,也是 RAG 检索质量的关键。

目录
  1. 可视化演示
  2. 搜索排序概述
  3. TF-IDF 原理
  4. BM25 词频饱和
  5. 理想文档长度
  6. 多字段打分
  7. function_score 定制
  8. 调优实践
  9. AI 应用场景
  10. Python 演示
  11. 常见误区
  12. 面试题

可视化演示

展示TF-IDF到BM25的评分演进,对比线性词频与饱和曲线的差异,直观呈现字段长度归一化和多字段打分对搜索排序的影响。

本节配有交互动效(进入视口后自动加载,约 3KB)。

TF-IDF:线性词频权重 TF-IDF中词频线性增长,高频词过度加权 BM25引入词频饱和+字段长度归一化 BM25解决了TF-IDF词频无限增长的缺陷

搜索排序概述

红娘的办公室里,桌上有“必须见一面”与“再看一眼”两摞档案,这是最原始的二分法。可很快她发现:用户要的不是“过没过线”,而是“谁排在最上面”。给每份档案打一个匹配度数字,从高到低排成一列,才算真正高效。搜索引擎面临的处境一模一样——用户敲下查询词,文档库里的候选千千万,系统必须在一瞬间给出一个有先后次序的答案。

在搜索引擎内部,这个任务分为两步:召回与排序。召回借助倒排索引,先筛出与查询词相关的候选文档;排序阶段再逐一打分,按分数从高到低返回。这个分数就是相关性评分(relevance score)。Elasticsearch 的排序阶段并非一个黑盒,而是一条清晰的公式链:命中的查询词越多越加分,词越稀有越加分,词在文档里出现得越充分越加分。

红娘把“综合匹配分”定为公式后,接下来每一节都在升级其中的一环:先搞清“出现次数”怎么算才不笨(TF-IDF),再加入“说多了就腻”的饱和(BM25),然后处理长短档案(长度归一化),最后分栏目加权(多字段)与定制加分(function_score)。整本打分手册就这样一页页丰满起来。

score(D,Q)=coord(Q,D)×∑t∈Q(idf(t)×tf_norm(t,D))\text{score}(D, Q) = \text{coord}(Q, D) \times \sum_{t \in Q} \left( \text{idf}(t) \times \text{tf\_norm}(t, D) \right)
这条公式是 Elasticsearch 打分的主干:协调因子负责“查全多少”,求和负责“逐词累加证据”,IDF 负责“词的稀有度”,词频与归一化负责“出现得够不够、浓不浓”。
  1. 协调因子 coord衡量查询中有多少个词真的出现在文档里,命中词越多,说明文档覆盖需求越全面,给一个整体加成。
    coord(Q,D)\text{coord}(Q, D)
  2. 对查询词求和把查询里每个词单独打分再相加,让多个证据互相叠加,而不是只看某一个词。
    ∑t∈Q\sum_{t \in Q}
  3. 逆文档频率 idf(t)衡量这个词在整个文档集合里到底多稀有,越稀有越能区分不同文档,权重越大。
    idf(t)\text{idf}(t)
  4. 词频与归一化 tf_norm词在文档里出现得越多贡献越大,但会结合文档长度做归一,避免长文档天然占便宜。
    tf_norm(t,D)\text{tf\_norm}(t, D)

TF-IDF 原理

红娘的第一版规则只有两条直觉:一,要求的关键词在档案里出现得越多,说明对方越符合,这是词频;二,越是人人都写、毫无特色的要求(比如“会吃饭”),匹配上了也毫无价值;越是只有极少数人写的要求(比如“会开挖掘机”),一旦匹配就是强烈命中,这是稀有度。常见词看次数,稀有词看身份,两条线索相乘。

这套直觉在信息检索领域叫 TF-IDF。TF(Term Frequency)统计查询词在文档里出现的次数;IDF(Inverse Document Frequency)用文档总数除以包含该词的文档数再取对数,衡量一个词的“身份稀缺度”。两者相乘,就是经典的 TF-IDF 相关度。

TF-IDF 第一次让“有多合适”变成可计算的数字,但两个漏洞立刻暴露:词频是线性的,把关键词堆 50 次分数就翻十倍,注水严重;长文档天然词频高,同样一句话,写在长文里比写在短文里显得更“重要”。红娘很快发现,那些把“旅行”写满三页的档案反而最可疑——于是 BM25 登场了。

TF-IDF(t,d)=tf(t,d)×log⁡(Ndf(t))\text{TF-IDF}(t, d) = \text{tf}(t, d) \times \log\left(\frac{N}{\text{df}(t)}\right)
简单说:一个词在文档里出现越多次,同时在全局越罕见,它的 TF-IDF 值就越高。乘积让“文中频率”与“全局稀有度”互相约束。
  1. 词频 tf(t,d)统计词 t 在文档 d 里出现的次数,出现越多,说明文档越聚焦在这个概念上。
    tf(t,d)\text{tf}(t, d)
  2. 文档总数 N索引中全部文档的数量,它是计算稀有度的整体参照系。
    NN
  3. 文档频率 df(t)统计包含词 t 的文档有多少篇,注意是篇数而非出现次数。
    df(t)\text{df}(t)
  4. 稀有度对数文档越多、含该词的文档越少,比值越大;取对数是为了防止比值悬殊带来的分数爆炸。
    log⁡(Ndf(t))\log\left(\frac{N}{\text{df}(t)}\right)
  5. 相乘合成把“文中出现次数”与“全局稀有度”乘起来,两个信号互相制衡,得到最终 TF-IDF 分。
    tf(t,d)×log⁡(Ndf(t))\text{tf}(t, d) \times \log\left(\frac{N}{\text{df}(t)}\right)

BM25 词频饱和

红娘学乖了一条人情世故:一个人说三遍“我爱旅行”非常可信,说十遍就开始像祥林嫂,说五十遍基本可以断定是复制粘贴。心动感不会随着重复次数成倍增加,这叫词频的饱和效应。在新规则里,每多重复一次,边际收益都在递减。

把这种直觉数学化的正是 BM25(Best Matching 25),它是概率检索模型的代表作,也是 Elasticsearch 5.0 之后的默认打分算法。BM25 把每个查询词的贡献拆成三块相乘:平滑后的 IDF、饱和的词频项、长度归一化因子。整体公式如下:

词频饱和项画成曲线,是一条先陡后平的渐近线:开头每多出现一次都明显加分,到后面几乎纹丝不动。参数 k1 控制“腻得有多快”,默认 1.2;k1 越大,饱和越慢,词频差异越能拉开分差。红娘在档案上画圈,画到第十个圈时连自己都烦了——k1 就是那支让她保持克制的笔。

score(D,Q)=∑i=1nIDF(qi)×f(qi,D)×(k1+1)f(qi,D)+k1×(1−b+b×∣D∣avgdl)\text{score}(D, Q) = \sum_{i=1}^{n} \text{IDF}(q_i) \times \frac{f(q_i, D) \times (k_1 + 1)}{f(q_i, D) + k_1 \times \left(1 - b + b \times \frac{|D|}{\text{avgdl}}\right)}
BM25 与 TF-IDF 最大的不同藏在那个分式里:词频 f 既出现在分子又出现在分母,当 f 很大时分数逼近上限,不会无限增长——这就是“话说三遍就腻”的数学表达。
  1. 对查询词累加查询 Q 包含 n 个词,每个词独立算出贡献后求和,多词查询就是多份证据叠加。
    ∑i=1n\sum_{i=1}^{n}
  2. BM25 版逆文档频率与 TF-IDF 的 log 类似,但加了 0.5 平滑项,避免某个词出现在全部文档时出现怪异负值。
    IDF(qi)=ln⁡(1+N−df(qi)+0.5df(qi)+0.5)\text{IDF}(q_i) = \ln\left(1 + \frac{N - \text{df}(q_i) + 0.5}{\text{df}(q_i) + 0.5}\right)
  3. 词频 f(q_i,D)词 q_i 在文档 D 中出现的次数,它是饱和曲线横轴上的输入变量。
    f(qi,D)f(q_i, D)
  4. 词频饱和项分子分母都含词频,f 很小时近似线性,f 越大越逼近上限 k1+1,重复次数的边际收益递减。
    f(qi,D)×(k1+1)f(qi,D)+k1×(1−b+b×∣D∣avgdl)\frac{f(q_i,D) \times (k_1 + 1)}{f(q_i,D) + k_1 \times \left(1 - b + b \times \frac{|D|}{\text{avgdl}}\right)}
  5. 长度归一化分母用平均长度 avgdl 校准文档长度,避免长文档因为分母偏大而系统性吃亏,这一块正是“理想文档长度”的来源。
    k1×(1−b+b×∣D∣avgdl)k_1 \times \left(1 - b + b \times \frac{|D|}{\text{avgdl}}\right)

理想文档长度

同是写一句“爱旅行”,写在 500 字的小卡片上,是浓得化不开的人设;写在 5 万字自传第 409 页,只是路过的一笔。红娘打分的另一条铁律由此诞生:文档越短,一个词的“浓度”越高,越接近铁证。搜索引擎里这叫字段长度归一化(field length normalization),也叫“理想文档长度”。

BM25 没有拿文档绝对长度直接做分母,而是用当前文档长度与集合平均长度之比来校准,并由参数 b 控制惩罚力度。归一化因子如下:

b=0 时红娘完全不看档案厚薄,长短一视同仁;b 越接近 1,长档案里那句“爱旅行”越被稀释。Elasticsearch 默认 b=0.75,是个多年实践折中的稳妥值。遇到全是短标题的商品库,可以调高 b 让“标题党”出头;遇到全是长报告的文档库,则要调低 b,防止长文档全军覆没。

1−b+b×∣D∣avgdl1 - b + b \times \frac{|D|}{\text{avgdl}}
这个因子出现在 BM25 分母里:文档越长,比值越大,分母越大,分数被稀释得越厉害。b 就是“长度歧视”的强度开关。
  1. 当前文档长度 |D|文档包含的词数,它是长度惩罚的输入变量,词数越多分母越大。
    ∣D∣|D|
  2. 集合平均长度 avgdl所有文档长度的平均值,是长度的“基准秤砣”,每篇文档都跟它比较。
    avgdl\text{avgdl}
  3. 相对长度比当前文档是平均长度的几倍,大于 1 表示偏长,小于 1 表示偏短。
    ∣D∣avgdl\frac{|D|}{\text{avgdl}}
  4. 惩罚系数 b0 到 1 之间的旋钮,控制长度因素对打分的干预程度,b 越大,长文档被稀释越厉害。
    1−b+b×∣D∣avgdl1 - b + b \times \frac{|D|}{\text{avgdl}}

多字段打分

红娘手里的档案其实分好几个栏目:基本信息、兴趣爱好、自我评价。兴趣栏写“旅行”和学历栏捎带“旅行”,含义完全不同。聪明的红娘会给不同栏目配不同权重:兴趣爱好栏更值钱,基本信息栏是及格线。搜索引擎里的文档同样由多个字段组成,标题、正文、标签各司其职。

Elasticsearch 的每个字段都可以独立计算一次 BM25 分数,再把它们组合起来。组合有两大流派:一是把各字段分数加权求和,让所有证据一起说话,对应 multi_match 的 most_fields 策略;二是只取分数最高的那个字段,相信“最响亮的声音”,对应 best_fields 策略。

实际项目中,标题字段给 3 倍权重、标签字段 1.5 倍、正文字段 1 倍,是再常见不过的配置——这就像一场分栏目加权、各取所长的红娘评审。加权求和让“证据越多越好”,取最大值让“最强项说了算”,二者各有用武之地。

scorebool=∑f∈Fwf⋅scoref,scorebest=max⁡f∈F(wf⋅scoref)\text{score}_{\text{bool}} = \sum_{f \in F} w_f \cdot \text{score}_f, \qquad \text{score}_{\text{best}} = \max_{f \in F} (w_f \cdot \text{score}_f)
左边是“加权求和”:所有字段的证据累加,适合希望查得全的场景;右边是“取最大值”:只看最匹配的那个字段,适合“一技之长即可”的场景。
  1. 字段权重 w_f业务赋予每个字段的重要度,标题常常比正文更值钱,权重越高影响越大。
    wfw_f
  2. 单字段 BM25 分 score_f把字段内容当作独立的小文档,单独跑一次 BM25 打分。
    scoref\text{score}_f
  3. 加权求和所有字段的证据一起累加,字段越多、越全面分数越高,适合“广撒网”的搜索场景。
    ∑f∈Fwf⋅scoref\sum_{f \in F} w_f \cdot \text{score}_f
  4. 取最大值只保留最强字段的分数,适合“一项专精就足够”的场景,避免弱字段拖后腿。
    max⁡f∈F(wf⋅scoref)\max_{f \in F} (w_f \cdot \text{score}_f)

function_score 定制

基础分是“标准答案”,但红娘总被要求开小灶:央企工作加分、同城加分、年龄差太大减分。这些业务规则与词语匹配无关,却切切实实影响“合不合适”。搜索引擎给这类需求留了一扇后门:function_score 查询。

function_score 在 BM25 原始分之上叠加自定义函数。最简单的用法是给通过过滤条件的文档乘一个固定权重;常见的是衰减函数——按数值字段(如发布时间、地理位置、价格)离理想点的远近来平滑降分;还可以干脆跑一段脚本算出任意想要的因子。

红娘的“同城加 3 分”,落到系统里就是给城市字段命中的文档乘一个加分因子;“刚发布的新闻优先”就是给发布时间套一条高斯衰减曲线,越旧越淡。function_score 是把业务经验翻译成数学规则的最后一公里,但必须克制使用——权重开得太大,会把 BM25 辛苦算出的文本相关度冲得干干净净。

final_score=query_score×∏j=1mfactorj\text{final\_score} = \text{query\_score} \times \prod_{j=1}^{m} \text{factor}_j
默认的 multiply 模式把原始查询分与所有自定义因子连乘。原始分越高、因子越多,最终分被放大或缩小得越明显,这就是“定制加分”的数学模样。
  1. 原始查询分 query_scoreBM25 等原生打分算出的文本相关度,是定制加分的底座。
    query_score\text{query\_score}
  2. 定制因子 factor_j每个函数产出一个因子,可以是固定 weight、衰减函数值或脚本返回值。
    factorj\text{factor}_j
  3. 连乘组合默认 multiply 模式把所有因子相乘,越相关的文档被放大得越明显,同时也可能被小因子压下去。
    ∏j=1mfactorj\prod_{j=1}^{m} \text{factor}_j
  4. 其他组合模式除了连乘,还能用 sum 把因子累加,或用 replace 完全替换原始分,由 boost_mode 控制。
    sum: query_score+∑j=1mfactorj\text{sum: } \text{query\_score} + \sum_{j=1}^{m} \text{factor}_j

调优实践

红娘不敢拍脑袋定规则,她会把三年前的配对数据翻出来当考卷,让新旧规则各跑一遍,看哪套规则排出的前三名成功率更高。调参的本质,就是一场可重复、可对比、可回归的实验。搜索调优也一样,改一个参数之前,先想清楚观察指标是什么。

搜索调优的关键旋钮其实就那几颗:k1 控制词频的差异化程度,b 控制长度惩罚力度,字段 boost 控制业务权重,function_score 承载自定义规则。不同场景参数取向完全不同:短文本商品库、长文知识库、新闻时效库,各有各的“甜点区间”。一个典型的加权调优写法如下:

一个可落地的调优流程是:发现问题(该靠前的文档靠后了)→ 用 explain 拆解分数构成 → 调整旋钮 → 用标注好的查询集做回归对比 → 上线观察。红娘最终会沉淀出一套属于自己的“评分手册”,而系统里那几颗旋钮,就是她反复校准后留下的刻痕。

final=3×scoreBM25(title)+1×scoreBM25(body)\text{final} = 3 \times \text{score}_{\text{BM25}}(\text{title}) + 1 \times \text{score}_{\text{BM25}}(\text{body})
给标题字段 3 倍权重、正文字段 1 倍权重再求和,是最常见的调优组合,本质就是“业务认为哪块内容更值钱,就让它的声音更大”。
  1. 标题字段分数商品或文章标题的 BM25 分,标题匹配查询词后得到,是排序的主信号。
    scoreBM25(title)\text{score}_{\text{BM25}}(\text{title})
  2. 标题权重 3业务认为标题匹配比正文重要三倍,直接乘 3 放大它的影响。
    3×3 \times
  3. 正文字段分数正文的 BM25 分,正文更长、词频分散,通常贡献较小但稳定。
    scoreBM25(body)\text{score}_{\text{BM25}}(\text{body})
  4. 权重 1 与求和正文按原样计入,两项相加得到最终排序分,整个式子就是一次标准的字段加权。
    3×scoreBM25(title)+scoreBM25(body)3 \times \text{score}_{\text{BM25}}(\text{title}) + \text{score}_{\text{BM25}}(\text{body})

AI 应用场景

电商搜索排序调优

阶段:检索排序与相关性调优

解决的问题:传统做法直接用 BM25 默认参数,结果“堆关键词”的长标题商品总霸占前排,用户真正想要的精准商品沉到后面。通过调低 k1 让词频饱和来得更快、给标题字段加大 boost、再用 function_score 给促销品加权,排序就能贴合业务目标。

具体案例:某电商搜索团队把商品标题字段 boost 设为 3、品牌字段设为 2,同时把 b 调低到 0.6 避免长标题被过度惩罚,再对促销商品叠加固定权重因子。上线后搜索点击率显著提升,首屏商品与用户意图的匹配度明显改善。

企业知识库检索与 RAG 召回

阶段:检索召回与排序

解决的问题:企业内部知识库文档长短悬殊,默认 BM25 下长文档要么永远占优、要么永远垫底;同时旧文档和新政策文档混在一起。用 b=0.6 温和处理长度归一化,标题字段加权,再给“最后更新时间”套一条高斯衰减曲线,让新文档浮出水面。

具体案例:某公司 50 万篇文档的知识库接入 BM25 排序后,员工搜索“报销新规”,带时间衰减的 function_score 让 2024 年的新规定排在旧版本前面,首屏命中率显著提升,RAG 问答的检索质量随之改善。

搜索效果回归实验

阶段:效果评估与参数调优

解决的问题:调参无据可依,改一个参数全站结果大变样,上线后才发现效果变差。用人工标注查询集 + 排序评价指标做回归对比,让每次调参都有数据背书。

具体案例:搜索团队维护了 200 条带人工标注的查询集,每周跑一次排序评测,对比新旧参数下的文档排序质量;每次调整 k1、b 或 boost 都先过一遍回归测试,再决定是否上线。

Python 演示

python61 行
import mathfrom collections import Counter  class BM25Scorer:    def __init__(self, corpus, k1=1.2, b=0.75):        self.corpus = corpus        self.k1 = k1        self.b = b        self.doc_count = len(corpus)        self.doc_lengths = [len(doc.split()) for doc in corpus]        self.avgdl = sum(self.doc_lengths) / float(self.doc_count)        self.df_map = Counter()        self.tf_maps = []        for doc in corpus:            tokens = doc.split()            freq = Counter(tokens)            self.tf_maps.append(freq)            for word in set(tokens):                self.df_map[word] += 1     def idf(self, word):        df = self.df_map.get(word, 0)        return math.log(1.0 + (self.doc_count - df + 0.5) / (df + 0.5))     def score(self, query, doc_id):        total = 0.0        dl = self.doc_lengths[doc_id]        tf_map = self.tf_maps[doc_id]        for word in query.split():            f = tf_map.get(word, 0)            if f == 0:                continue            norm = 1.0 - self.b + self.b * dl / self.avgdl            tf_component = f * (self.k1 + 1.0) / (f + self.k1 * norm)            total += self.idf(word) * tf_component        return total  def main():    # 玩具语料: 5 篇英文文档    corpus = [        "the cat hunts mice at night",        "the owl is a night hunter and eats mice",        "python is a language for text search",        "search engines use python for scoring",        "mice steal grain from farm stores",    ]    query = "mice night"    scorer = BM25Scorer(corpus)    result = sorted(        range(len(corpus)),        key=lambda i: scorer.score(query, i),        reverse=True    )    for i in result:        print("doc %d score=%.4f  %s" % (i, scorer.score(query, i), corpus[i]))  if __name__ == "__main__":    main()
目的:用纯 Python 实现 BM25 全流程,帮你直观看到“词频 + IDF + 长度归一化”如何合成一个排序分。
  1. self.avgdl = sum(self.doc_lengths) / float(self.doc_count)算出集合平均长度,长度归一化全靠它当“基准秤砣”
  2. self.df_map[word] += 1统计每个词出现在多少篇文档里,这是 IDF 的原始输入
  3. return math.log(1.0 + (self.doc_count - df + 0.5) / (df + 0.5))BM25 平滑版 IDF,加了 0.5 防止分母为零
  4. norm = 1.0 - self.b + self.b * dl / self.avgdl长度归一化因子,文档越长分母越大,分数被稀释
  5. tf_component = f * (self.k1 + 1.0) / (f + self.k1 * norm)饱和词频项,f 增大时分值逼近上限
  6. total += self.idf(word) * tf_component每个词的贡献累加,得到文档最终相关性分
  7. key=lambda i: scorer.score(query, i), reverse=True按分数降序排列,把最相关的文档排最前

常见误区

误区我写文档时特意把用户常搜的词多重复几遍,搜索排名一定能上去,反正词频是越多分越高。

正解BM25 的词频项是一条饱和曲线,出现 3 次和出现 10 次分差很小,堆到 50 次几乎不再加分。真正拉开差距的是内容匹配质量、字段权重与长度归一化。“堆词”在搜索引擎里反而可能被判定为作弊信号。就像红娘听到对方把“爱旅行”重复 50 遍,不仅不加分,还会怀疑档案造假。

为何常见:TF-IDF 的线性词频直觉太深入人心,很多人不知道 BM25 已经引入了饱和机制,仍用“越多越好”的旧观念指导实践。

误区IDF 大的词一定是好词,调权时应该给罕见词疯狂加权重,反正越稀有越有价值。

正解IDF 只反映区分度,不反映相关性。一个词在数据里极其罕见,可能只是因为它是错别字或冷门专有名词,命中它并不能代表文档相关。BM25 的 IDF 还做了平滑,防止极端值统治整个分数。红娘不会因为只有一人写了“会手语”就把对方排第一,她还要看其他栏目与整体匹配度。

为何常见:把“稀有等于有价值”的日常直觉直接搬到检索里,忽略了相关性是多个信号综合评判的结果。

误区长文档总是稀释关键词、体验差,把 b 调到 1,彻底惩罚长文档就一劳永逸了。

正解b 控制的是“相对平均长度”的惩罚程度。把所有长文档都打死,短标题文档会霸榜,但短文档信息量少、主题可能不聚焦,结果既不相关又不完整。b=0.75 是多年实践的折中值,具体取值要靠实验数据说话。红娘既不会无视档案厚薄,也不会一票否决所有长自传。

为何常见:把“长文档体验不好”的经验绝对化,忽略了长度惩罚的本意是校准“关键词浓度”,而不是筛选文章体裁。

误区我把标题字段 boost 调大,这个字段相关的文档就一定能排到前面,甚至原本不匹配的词也能被加权捞出来。

正解boost 是给“已经匹配上”的分数做乘法,不匹配的文档该是 0 分还是 0 分。boost 只放大已有信号,不能创造匹配;function_score 的 weight 也只在过滤条件命中的文档上生效。就像红娘的“同城加分”只作用于通过初筛的候选人,不会把基本要求都不符合的档案捞回来。

为何常见:把“加权”误解为“添加”,没理解 boost 本质上是乘性操作而非加性操作。

面试题

Q1. BM25 算法中 k1 参数的主要作用是什么?

单选题 · easy

  • A.控制 IDF 的缩放幅度
  • B.控制词频饱和速度← 正确答案
  • C.控制文档长度惩罚
  • D.控制查询词的权重

答案:B。k1 是 BM25 词频饱和项里的参数,控制重复出现的边际收益递减速度。k1 越大饱和越慢,词频差异越能拉开分差;k1 越小,出现两三次就接近打满。A 说的是 IDF 的缩放,C 对应 b 参数,D 在 BM25 中不存在。就像红娘对“我爱旅行”说几遍才腻,k1 决定她的耐心程度。

Q2. BM25 打分公式中包含哪些可调参数?

多选题 · easy

  • A.k1 词频饱和参数← 正确答案
  • B.b 长度惩罚参数← 正确答案
  • C.a 窗口大小参数
  • D.g 梯度下降率

答案:AB。BM25 的可调参数就是 k1 和 b:k1 控制词频饱和速度,b 控制长度归一化强度。C 中“窗口大小”是 NLP 里的概念,D 中“梯度下降”是机器学习训练的概念,两者都不属于 BM25 打分模型。就像红娘的评分手册只有“腻不腻”和“介不介意档案厚”两个旋钮。

Q3. 相比 TF-IDF,BM25 最重要的改进是什么?

单选题 · mid

  • A.引入词频饱和机制← 正确答案
  • B.加入分词器支持
  • C.支持多种检索语言
  • D.提高索引构建速度

答案:A。TF-IDF 的词频是线性的,堆词就能刷分;BM25 把线性词频换成饱和曲线,重复出现边际收益递减,还加了长度归一化。B 分词属于预处理环节,C 多语言支持与打分算法无关,D 索引构建速度是存储引擎的范畴。就像红娘不再数“我爱旅行”说了几遍,而是看说到第几句就不再心动。

Q4. 文档长度归一化中,avgdl 表示什么意思?

单选题 · easy

  • A.全部文档字数总和
  • B.文档集合平均长度← 正确答案
  • C.查询关键词总长度
  • D.索引分片的个数

答案:B。avgdl 是 average document length 的缩写,即文档集合的平均长度,长度归一化以它为基准:当前文档长度与它相比,得出“偏长还是偏短”。A 是总长度不是平均,C 是查询维度,D 是分布式存储概念,都与 avgdl 无关。

Q5. 一个关键词在短文档里出现一次,比在长文档里出现一次更相关,主要靠哪个机制实现?

单选题 · mid

  • A.逆文档频率 IDF
  • B.字段长度归一化← 正确答案
  • C.词频饱和曲线
  • D.查询权重提升

答案:B。短文档出现一次关键词“浓度高”,靠的是长度归一化:同样的词频除以更短的长度,得分占比更大。A 管的是词的全局稀有度,C 管重复次数的边际递减,D 是字段层面的权重,都不负责“同样一次在不同长度文档里的价值差”。

Q6. 哪些操作可以调整搜索结果的相关性排序?

多选题 · mid

  • A.调整 k1 和 b 参数← 正确答案
  • B.给字段设置不同 boost← 正确答案
  • C.使用 function_score← 正确答案
  • D.修改索引分片数

答案:ABC。k1 和 b 是 BM25 固有参数,字段 boost 是多字段打分的权重,function_score 是叠加自定义因子,三者的修改都会直接改变分数。而 D 修改分片数只影响存储分布与并发性能,不改变打分公式。就像红娘改的是评分标准,而不是档案柜的摆放方式。

Q7. 关于 BM25 的 IDF 项,以下哪个说法正确?

单选题 · hard

  • A.罕见词的 IDF 通常更高← 正确答案
  • B.高频词的 IDF 必然为负
  • C.IDF 与文档集合无关
  • D.IDF 恒定等于 1.0

答案:A。文档频率越低,IDF 越高,罕见词区分度大。B 错误,高频词 IDF 趋近于 0 但不会轻易为负,即使为负也只是个平滑信号;C 明显错误,IDF 依赖整个文档集合统计;D 更离谱,IDF 随词的稀有度变化。就像红娘眼里,“会开挖掘机”这种冷门要求一旦匹配,身份的稀缺感格外强。

Q8. function_score 中 gauss 衰减函数最适合什么场景?

单选题 · mid

  • A.按距离或时间衰减加权← 正确答案
  • B.精确匹配后固定加分
  • C.对词频做饱和压缩
  • D.把分数替换成常数

答案:A。gauss 衰减函数按数值字段(时间、位置、价格)离理想点的距离平滑降分,越接近越相关,适合“刚发布的新闻优先”“离用户近的门店优先”这类场景。B 固定加分是 weight 的职责,C 属于 k1 做的事情,D 是 replace 模式而非衰减函数的能力。

Q9. BM25 对一篇文档打分时,结果可能受哪些因素影响?

多选题 · hard

  • A.词频与文档长度← 正确答案
  • B.词的文档频率← 正确答案
  • C.集合平均长度← 正确答案
  • D.硬件内存大小

答案:ABC。词频、文档长度、文档频率、集合平均长度全部是 BM25 公式的输入变量。D 硬件内存只影响查询性能,不进入打分公式。就像红娘的评分只取决于档案内容和她的评分标准,与办公桌抽屉有多大无关。

Q10. 想让“标题”字段的匹配对排序贡献更大,最直接的方式是?

单选题 · mid

  • A.给字段设置更大 boost← 正确答案
  • B.删除其他字段
  • C.降低 k1 参数
  • D.提高 b 参数值

答案:A。给标题字段设更大的 boost,会直接放大标题匹配的分数贡献,这是多字段打分最常用的手段。B 删除字段会丢失召回信息;C 的 k1 是全局词频饱和参数,不针对具体字段;D 的 b 是长度惩罚参数,与“标题更值钱”这个诉求无关。