不是向量相似度,而是基于倒排索引的动态统计打分
❓ 一个更隐蔽的误解:搜索引擎会把“索引词”变成向量吗?
很多人知道 Elasticsearch 默认不是靠文档向量打分,但又产生了一个新疑问:
“那是不是搜索引擎先把每个索引词(比如‘人工智能’)变成一个向量,然后把我的搜索词也变成向量,再看它们是否匹配?”
答案仍然是否定的。
在传统的关键词搜索引擎(如 Lucene、Elasticsearch 默认模式)中:
- 词项(term)只是一个字符串标识符,比如
"人工智能"、"工具"; - 它没有 embedding,没有数值向量,不参与任何向量运算;
- 匹配过程是精确的字符串相等比较:只有当你的查询词分词后得到的 term 和索引中的 term 完全一致(字节级相同),才算匹配。
换句话说:
搜索引擎不是在“找语义相近的词”,而是在“找完全相同的词”。
这就像图书馆的目录卡——只有你输入的书名一字不差,才能找到对应的书。它不会因为你说“AI”就自动找到“人工智能”的书(除非你显式配置了同义词扩展)。
那么,TF-IDF 或 BM25 中的权重(比如 IDF 值)是不是“词向量”? 也不是。 IDF 只是一个标量分数(一个数字),用来衡量这个词有多“重要”或“稀有”,但它不携带方向、不构成空间、不能做相似度计算。它只是打分公式里的一个系数。
✅ 总结一句话:
在 BM25 这类系统中,词是符号,不是向量;匹配靠相等,不是相似。
那什么时候词才会被向量化?
| 场景 | 是否向量化 | 说明 |
|---|---|---|
| 传统关键词搜索(BM25) | ❌ 否 | 词是字符串,匹配靠 exact match |
| 同义词扩展(Synonym Graph) | ❌ 否 | 仍是规则映射,非向量 |
| Word2Vec / GloVe 词向量 | ✅ 是 | 通常用于 NLP 预处理,不直接用于 Lucene 检索 |
| Dense Retrieval(稠密检索) | ✅ 是 | 用 BERT 等模型将整个查询/文档编码为向量,通过 ANN 检索 |
| ColBERT、SPLADE 等 late interaction 模型 | ✅ 是 | 对词做向量表示,但属于前沿研究,非默认行为 |
所以,如果你没显式启用向量搜索功能(比如 Elasticsearch 的 dense_vector + knn 查询),那你用的就还是纯符号匹配 + 统计打分的 BM25。
🔍 那 BM25 到底怎么打分?我们一步步拆解
假设你搜了两个词:“人工智能 工具”。
搜索引擎会分别评估每个词对每篇文档的“贡献”,然后加起来。
第1步:看一个词在文档里出现的次数(TF)
比如,“人工智能”在某篇文章里出现了 3 次。
直觉上:出现越多,越相关? 但不能无限加分——如果一篇文章重复刷“人工智能”100遍,它真的更好吗?不一定。
所以 BM25 引入了“饱和机制”:次数多了,加分就变慢。
第2步:看这个词有多“稀有”(IDF)
- 如果“的”“是”这种常见词,哪怕出现 100 次,也不该加分太多;
- 但“量子计算”“大模型蒸馏”这种专业词,只要出现一次,就很有价值。
这就是 IDF(逆文档频率):
一个词越少见,它的 IDF 越高,权重越大。
第3步:考虑文章长短(长度归一化)
一篇 1000 字的文章提到“人工智能”3 次, 和一篇 100 字的文章提到 3 次, 哪个更专注?
显然是短文!所以 BM25 会惩罚过长的文档,避免它们靠堆字数占便宜。
📐 把上面的逻辑变成公式
对于一个词 和一篇文档 ,BM25 的得分是:
别被吓到!我们对照上面三点来理解:
| 符号 | 含义 | 获取方式 |
|---|---|---|
| 词项 在文档 中的出现次数(词频)(即 ) | 索引时写入倒排列表 | |
| 文档长度,即:包含的词项(term)总数 | 索引时写入倒排列表 | |
| 所有文档的平均长度 | 索引级别元数据 | |
| 逆文档频率,衡量词的稀有程度 | 预计算: | |
| 索引中文档总数 | 全局统计量 | |
| 包含词项 的文档数量 | 由倒排索引的文档频率得出 | |
| 控制词频饱和度(默认 1.2) | 可配置参数 | |
| 控制长度归一化强度(默认 0.75) | 可配置参数 |
💡 这些数据(、、 等)都是建索引时提前算好存下来的,查询时直接用,所以速度极快。
📊关于“文档的平均长度“的说明
1、“文档长度”指什么?
- 不是字节数,也不是字符数;
- 而是经过分词后,文档中包含的词项(term)总数。
✅ 举例:
- 文档 A:
"人工智能是未来的技术。"分词后:["人工智能", "是", "未来", "的", "技术"]→ 长度 - 文档 B:一篇 1000 字的技术白皮书,分词后有 850 个词 →
💡 这个长度在建索引时就会计算好,并存储在字段的
norms中(可关闭以节省空间)。
2、“所有文档的平均长度”怎么算?
假设你的索引里有 3 篇文档,长度分别是:
那么:
在真实系统中(如 Elasticsearch),这个值是索引级别(index-level)的全局统计量,每次新增或删除文档时会动态更新(或近似更新)。
3、为什么需要 avgdl?——解决“长文档作弊”问题
想象两个文档都包含查询词 “大模型” 3 次:
- 文档 X:短文,共 50 个词 → “大模型” 出现 3 次,占比 6%
- 文档 Y:长报告,共 3000 个词 → “大模型” 出现 3 次,占比 0.1%
直觉上,文档 X 更聚焦于“大模型”,应该排得更靠前。
但如果不考虑长度,仅看词频 ,两者 TF 部分得分一样,不公平。
👉 BM25 通过 引入长度惩罚:
- 如果 (文档偏长)→ 分母变大 → 整体分数降低;
- 如果 (文档偏短)→ 分母变小 → 分数更高(更专注)。
公式中的这一项: 就是动态调整 TF 饱和点的因子,其中 (默认 0.75)控制惩罚强度:
- :完全不考虑长度(退化为早期 TF-IDF);
- :完全按比例归一化。
🧪 举个真实例子
假设:
- 全库有 100 万篇文章()
- “人工智能”出现在 1 万篇文章中()
- 当前文章长度:200 词()
- 全库平均长度:150 词()
- “人工智能”在这篇文章中出现 3 次()
- 使用默认参数:,
1️⃣ 先算 IDF(衡量稀有度):
2️⃣ 再算 TF 的“有效得分”(考虑饱和和长度):
先算分母:
再算分子:
所以 TF 部分得分:
3️⃣ 最终这个词的贡献分:
如果另一个词“工具”贡献了 3.24 分,那这篇文档总分 ≈ 10.0。
🔁 闭环流程:从你的搜索词到最终排序结果
现在我们把整个过程串起来,看看当你输入 “人工智能 工具” 时,搜索引擎到底做了什么。
步骤 1️⃣:查询解析与分词
- 用户输入:
"人工智能 工具" - 经过分词器处理 → 得到两个词项:
注意:这里没有向量化,只是字符串切分。
步骤 2️⃣:查倒排索引,获取候选文档集合
对每个词项,分别查倒排索引:
"人工智能"→ 倒排列表:"工具"→ 倒排列表:
根据查询类型决定如何合并:
| 查询类型 | 合并方式 | 说明 |
|---|---|---|
match(默认) | OR:取并集 | 只要包含任一词就算候选 |
match + "operator": "and" | AND:取交集 | 必须同时包含两个词 |
match_phrase | 短语匹配 | 要求词序和邻近性 |
假设使用默认 match(OR 模式),则候选文档 = 所有出现在任一列表中的文档。
💡 实际系统会限制候选集大小(如 top 10,000),避免计算爆炸。
步骤 3️⃣:对每个候选文档,计算总分
对每个候选文档 ,执行:
- 检查它包含哪些查询词项;
- 对每个匹配的词项 ,用 BM25 公式计算 ;
- 将所有匹配词项的得分线性相加,得到文档总分:
✅ 这就是你在 Elasticsearch 中看到的
_score!
举个例子:
- 文档 包含 “人工智能”(得分 6.76)和 “工具”(得分 3.24)
- 总分 =
- 文档 只包含 “人工智能” → 总分 = 6.76
- 文档 只包含 “工具” → 总分 = 3.24
最终排序:
步骤 4️⃣:返回排序结果
系统按 _score 从高到低返回文档(可配合分页、过滤、高亮等)。
⚠️ 注意:BM25 不保证语义相关性! 如果你搜 “AI”,而文档写的是 “人工智能”,但没配合同义词,就完全匹配不上——因为
"AI" ≠ "人工智能"。
🧩 补充:布尔逻辑与打分的关系
- AND 查询:只有同时包含所有词的文档才进入打分阶段;
- OR 查询:包含任一词的文档都打分,但只累加它实际命中的词;
- NOT 查询:排除某些文档,不影响打分公式本身。
所有这些逻辑都在倒排索引的集合运算层完成,打分只发生在匹配之后。
✅ 关键结论(再说一遍)
- 没有文档向量,也没有词向量;
- 词项只是字符串符号,匹配靠 exact match;
- 所有计算都基于倒排索引中预存的统计信息;
- 打分是查询时动态计算的,但因为只涉及几个数字运算,所以极快;
- 最终得分 = 所有匹配词的 BM25 分数之和;
- 整个流程是:分词 → 倒排查找 → 布尔筛选 → term 级打分 → 求和 → 排序。
🧠 什么时候才用“向量化”?
当你启用语义搜索时,比如:
- 用 BERT 把整篇文档编码成一个 768 维向量;
- 把你的问题也编码成向量;
- 用 ANN(近似最近邻)找最相似的文档。
这才是真正的“向量匹配”。但这是新一代技术,和 BM25 属于不同范式。
目前工业界主流做法是:
BM25(关键词匹配) + 向量检索(语义匹配) → 混合搜索(Hybrid Search)
既保证精准召回,又覆盖语义泛化。
📌 总结一句话: BM25 不是向量化,而是一套基于统计的“现场打分规则”,高效、可解释、工程友好