文章目录
- 1. 算法介绍
- 2. 整体流程
-
- 2.1 📦 阶段一:离线预处理
- 2.2 🔍 阶段二:在线实时检索
- 3. 核心概念
-
- 3.1 系统词汇表
- 3.2 稀疏向量
- 3.3 文档-词项矩阵
- 4. 打分算法迭代演进
-
- 4.1 版本一:简单命中计数打分
- 4.2 版本二:TF 原始词频打分
- 4.3 版本三:TF‑IDF(词频‑逆文档频率)
-
- 步骤 1:计算 DF(文档频率)
- 步骤 2:权重反转
- 步骤 3:对数平滑得到标准 IDF
- 步骤 4:TF‑IDF 加权计算
- 5. TF-IDF 致命短板
1. 算法介绍
关键词检索(Keyword Search)属于信息检索技术的基础方法之一,是一种通过输入关键字获取文档信息的查询方式。
这种技术几十年来一直驱动着数据库和搜索引擎的检索。它的简单性和高效性,使其成为现代 RAG 系统检索的核心组成部分。
基本思路:统计文档与查询重叠词数量,重叠越多原始分数越高,但不理解语义,只看字面词共现。
示例,当前有三个做菜相关的文档:
- Doc1:做川味水煮牛肉,首选牛里脊,搭配豆芽莴笋打底。
- Doc2:这家川味菜馆的水煮牛肉支持外卖,可以在家点单食用。
- Doc3:这家川味老店生意火爆,很多食客会在家点麻辣火锅。
用户输入提问:
怎么自制川味水煮牛肉?
输入会进行关键词拆分为:怎么、自制、川味、水煮牛肉,根据关键词三个文档都会被召回:
| Doc1 | 讲解自制水煮牛肉做法,匹配用户意图 | 川味、水煮牛肉 | 2 |
| Doc2 | 介绍餐馆外卖服务,并非做菜教程 | 川味、水煮牛肉 | 2 |
| Doc3 | 介绍自制麻辣火锅,与水煮牛肉无关 | 川味 | 1 |
其中 Doc1、Doc2 字面命中数量一致,但语义相关性天差地别,简单的命中计数无法区分真实相关性。
2. 整体流程
TF‑IDF 的完整链路分为 知识库离线构建流程 和 用户在线检索流程 两大阶段:
2.1 📦 阶段一:离线预处理

一次性执行,知识库更新时重新跑:
I
D
F
(
w
o
r
d
)
=
log
(
N
D
F
(
w
o
r
d
)
)
IDF(word)=\\log\\left(\\frac{N}{DF(word)}\\right)
IDF(word)=log(DF(word)N)
N
N
N = 知识库文档总数;
D
F
DF
DF 越大(词语越通用),
I
D
F
IDF
IDF 分值越低。
T
F
‑
I
D
F
=
T
F
×
I
D
F
TF‑IDF = TF × IDF
TF‑IDF=TF×IDF 每个词语最终权重 = 局部词频 × 全局稀有度权重
2.2 🔍 阶段二:在线实时检索

每次用户提问执行:
3. 核心概念
3.1 系统词汇表
系统词汇表:整个知识库提前固定好的、不变化的全局词语清单,它给每一个词语分配唯一固定下标,用来统一所有文档向量的维度。
把全部文档里所有不重复的词收集、去重,整理成一份全局词列表,这份列表就是系统词汇表。
上面的 Doc1、Doc2、Doc3 三个做菜文档,收集去重后的系统词汇表(固定顺序,全局唯一):
| 0 | 川味 |
| 1 | 水煮牛肉 |
| 2 | 牛里脊 |
| 3 | 豆芽 |
| 4 | 莴笋 |
| 5 | 菜馆 |
| 6 | 外卖 |
| 7 | 麻辣火锅 |
3.2 稀疏向量
为了让知识库能够被检索,每个文档都会生成一个稀疏向量。
这些词频会被存储在一个向量中,这个向量为系统词汇表中的每个词都分配一个固定位置,向量中的每个数字,表示该词语在文本里出现的次数。
上面那套词汇表规则中,每个文档词频对应的向量为:
- Doc1:[1, 1, 1, 1, 1, 0, 0, 0]
- Doc2:[1, 1, 0, 0, 0, 1, 1, 0]
- Doc3:[1, 0, 0, 0, 0, 0, 0, 1]
向量的维度很高,可能有数万个位置,由于绝大多数位置存放的值都是 0 ,这类向量叫做稀疏向量(Sparse Vectors)。
和稠密向量(Dense Vector)对比:
| 生成方式 | 分词+统计公式,无神经网络 | 大模型/预训练Encoder推理输出 |
| 向量维度 | 等于词表大小(上万~几十万维) | 固定小维度(512/768/1024) |
| 向量特征 | 大量0,稀疏 | 数值连续非0,稠密 |
| 语义能力 | 仅字面匹配,不理解语义 | 承载语义,支持同义模糊匹配 |
| 相似度计算 | 余弦/点积 | 余弦相似度 |
| 检索定位 | 稀疏检索(关键词召回) | 稠密检索(语义召回) |
3.3 文档-词项矩阵
每一篇文档生成稀疏向量后,全部向量组合形成二维网格结构,这个表格叫文档-词项矩阵(Document-Term Matrix)。
结构定义:
- 行:词项(系统词汇表中)
- 列:单篇文档
关于单元格的取值,可以有多种形式,比如:
- One‑Hot 形式:1 代表词语在该文档出现,0 代表未出现,只标记存在与否,不关心词汇出现多少次。
- TF(词频)形式:单元格填入该词在文档中的实际出现次数。数值越大,说明这个词在当前文档里反复出现,主题关联性更强。
上面的 Doc1、Doc2、Doc3 词项‑文档矩阵(One‑Hot 形式):
| 川味 | 1 | 1 | 1 |
| 水煮牛肉 | 1 | 1 | 0 |
| 牛里脊 | 1 | 0 | 0 |
| 豆芽 | 1 | 0 | 0 |
| 莴笋 | 1 | 0 | 0 |
| 菜馆 | 0 | 1 | 0 |
| 外卖 | 0 | 1 | 0 |
| 麻辣火锅 | 0 | 0 | 1 |
有了这个矩阵之后,我们就把非结构化的自然语言文本,转换成了计算机可以直接运算的数值化结构化数据。
可以很方便地从一个词查找包含该词的所有文档,一般也叫倒排索引。因为通常我们是从文档出发,思考它包含哪些词(正向索引),这里是给定一个词语,列出所有包含这个词的文档。
| 川味 | Doc1,Doc2,Doc3 |
| 水煮牛肉 | Doc1,Doc2 |
| 牛里脊 | Doc1 |
| 豆芽 | Doc1 |
| 莴笋 | Doc1 |
| 菜馆 | Doc2 |
| 外卖 | Doc2 |
| 麻辣火锅 | Doc3 |
4. 打分算法迭代演进
至此,文档与查询语句各自都拥有对应的稀疏向量,检索器接收查询语句后,接下来便可对全部文档执行打分与排序操作。
三代矩阵对比总结:
- One‑Hot 矩阵:仅标记是否出现,无权重差异
- TF 词频矩阵:仅统计文档内部频次,无法抑制通用词汇
- TF‑IDF 矩阵:全局加权,稀有业务词汇获得高分,无区分度的高频词权重归零
4.1 版本一:简单命中计数打分
最基础的打分规则:每命中一个关键词,文档获得对应积分,关键词只要出现一次即得 1 分,重复出现不会额外加分,后续可基于累计分值完成相关性排序。
在 2.5 章节中的示例,查询文本:自制川味水煮牛肉?,提取全部关键词:自制、川味、水煮牛肉,命中文档:
| 自制 | 无匹配文档 |
| 川味 | Doc1,Doc2,Doc3 |
| 水煮牛肉 | Doc1,Doc2 |
每命中 1 个关键词得 1 分,这样就会得到一个得分排序:
- Doc1:川味 + 水煮牛肉 = 2 分
- Doc2:川味 + 水煮牛肉 = 2 分
- Doc3:川味 = 1 分
这种基础打分机制存在短板:它仅判断关键词是否存在于文档中,不会统计关键词在文本内的出现次数。但现实场景里,同一个关键词反复出现,往往代表这份文档和用户查询的相关性更强,该简单算法无法捕捉这层信号。
4.2 版本二:TF 原始词频打分
一种简易优化方案:文档中每出现一次关键词,就累加一次分值。
假设三篇文档内部词汇出现频次如下:
| 自制 | 2 | 0 | 0 |
| 川味 | 3 | 1 | 2 |
| 水煮牛肉 | 3 | 1 | 0 |
| TF总分 | 8 | 2 | 2 |
打分计算过程:
- Doc1:自制(2) + 川味(3) + 水煮牛肉(3) = 8 分
- Doc2:自制(0) + 川味(1) + 水煮牛肉(1) = 2 分
- Doc3:自制(0) + 川味(2) + 水煮牛肉(0) = 2 分
TF 词频只统计单个文档内部词语出现多少次,但它存在一个明显缺陷:无法区分词语本身的珍贵程度。有些高频通用词(如 自制、的)哪怕多次出现,对判断文档主题几乎没有区分价值;而小众专属词汇,才是判断相关性的核心线索。
4.3 版本三:TF‑IDF(词频‑逆文档频率)
TF-IDF 的全称是 Term Frequency-Inverse Document Frequency,中文叫词频 – 逆文档频率。它的核心思想很简单:如果一个词在某篇文章里出现很多次,但在其他文章里很少出现,那这个词对这篇文章就很重要 。
这个技术由两部分组成:
- TF(词频):衡量一个词在当前文档中出现的频率,出现越多越重要。
- IDF(逆文档频率):衡量一个词在整个文档集合中的稀有程度,越稀有的词权重越高。
IDF 这个概念最早由英国学者 Karen Spärck Jones 在 1972 年提出,后来与 TF 结合形成了现在广泛使用的 TF-IDF 算法 。是一种用于评估词语在文档中重要程度的统计方法,广泛应用于搜索引擎、文本分类和关键词提取等场景 。
IDF 的完整计算分为 4 个关键步骤,最终生成 TF‑IDF 加权词项‑文档矩阵。
步骤 1:计算 DF(文档频率)
文档频率
D
F
DF
DF 代表:整个文档库中,包含该词的文档占全部文档的比例。
计算公式:
D
F
(
w
o
r
d
)
=
包含该词的文档数量
文档库总文档数
DF(word) = \\frac{\\text{包含该词的文档数量}}{\\text{文档库总文档数}}
DF(word)=文档库总文档数包含该词的文档数量
D
F
DF
DF 值越大,代表这个词汇在语料中越普遍,区分文档差异的价值越低。
以本次案例为例,文档总数
N
=
3
N=3
N=3:
- 词「川味」出现在 3 篇文档:
D
F
=
3
3
=
1.0
DF=\\dfrac{3}{3}=1.0
DF=33=1.0 - 词「水煮牛肉」出现在 2 篇文档:
D
F
=
2
3
≈
0.67
DF=\\dfrac{2}{3}\\approx0.67
DF=32≈0.67 - 词「牛里脊」仅出现在 1 篇文档:
D
F
=
1
3
≈
0.33
DF=\\dfrac{1}{3}\\approx0.33
DF=31≈0.33
步骤 2:权重反转
DF 的数值逻辑和我们想要的打分逻辑是相反的:
- DF 大(到处都出现)→ 我们希望权重低
- DF 小(很少出现)→ 我们希望权重高
对 DF 取倒数,就是把分数逻辑翻转过来:
中间权重
=
1
D
F
(
w
o
r
d
)
=
总文档数量
包含该词的文档数量
\\text{中间权重} = \\frac{1}{DF(word)}=\\frac{\\text{总文档数量}}{\\text{包含该词的文档数量}}
中间权重=DF(word)1=包含该词的文档数量总文档数量
代入案例演算:
D
F
=
1.0
DF=1.0
DF=1.0,中间权重
1
1.0
=
1
\\displaystyle \\frac{1}{1.0}=1
1.01=1
D
F
≈
0.67
DF≈0.67
DF≈0.67,中间权重
1
0.67
≈
1.5
\\displaystyle \\frac{1}{0.67}≈1.5
0.671≈1.5
D
F
≈
0.33
DF≈0.33
DF≈0.33,中间权重
1
0.33
≈
3
\\displaystyle \\frac{1}{0.33}≈3
0.331≈3
| 川味 | 1.0 | 1 | 高频通用词,分值压低 |
| 水煮牛肉 | 0.67 | 1.5 | 中等稀有度,中等分值 |
| 牛里脊 | 0.33 | 3 | 稀有专属词,获得更高分值 |
直接取倒数会造成数值差距过大:稀有词权重爆炸放大。如果文档库很大(例如10000篇文档),只出现 1 次的词,中间权重直接等于 10000,分值会严重失衡,打分结果失真。
因此需要下一步:对数平滑压缩数值范围。
步骤 3:对数平滑得到标准 IDF
引入对数函数压缩权重区间,得到工程上标准的逆文档频率 IDF:
I
D
F
(
w
o
r
d
)
=
log
(
总文档数
包含该词的文档数
)
IDF(word)=\\log\\left(\\frac{\\text{总文档数}}{\\text{包含该词的文档数}}\\right)
IDF(word)=log(包含该词的文档数总文档数)
案例计算:
log
(
1
)
=
0
\\log(1)=0
log(1)=0
log
(
1.5
)
≈
0.41
\\log(1.5)≈0.41
log(1.5)≈0.41
log
(
3
)
≈
1.10
\\log(3)≈1.10
log(3)≈1.10
对数不会改变大小关系:稀有词依然分数更高,只是把巨大的差值压缩到一个合理的小数区间。全局高频词最终权重归零,不再干扰检索打分。
| 川味 | 3 | 1.0 |
1 1 1 |
0 0 0 |
| 水煮牛肉 | 2 | 0.67 |
1.5 1.5 1.5 |
0.41 0.41 0.41 |
| 牛里脊 | 1 | 0.33 |
3 3 3 |
1.10 1.10 1.10 |
步骤 4:TF‑IDF 加权计算
T
F
‑
I
D
F
TF‑IDF
TF‑IDF 的计算公式:
T
F
‑
I
D
F
(
w
o
r
d
,
d
o
c
)
=
T
F
(
w
o
r
d
,
d
o
c
)
×
I
D
F
(
w
o
r
d
)
\\boldsymbol{TF‑IDF(word,doc) = TF(word,doc) \\times IDF(word)}
TF‑IDF(word,doc)=TF(word,doc)×IDF(word)
其中:
-
T
F
(
w
o
r
d
,
d
o
c
)
TF(word,doc)
TF(word,doc):词在单篇文档内部的出现次数,代表词汇对这一篇文档的局部重要性 -
I
D
F
(
w
o
r
d
)
IDF(word)
IDF(word):词汇在整个文档库的全局权重,代表词汇本身的珍贵程度 -
T
F
‑
I
D
F
TF‑IDF
TF‑IDF:二者相乘,得到该词汇在这篇文档里的最终加权得分
假设 TF 原始词项‑文档矩阵:
| 川味 | 3 | 1 | 2 |
| 水煮牛肉 | 3 | 1 | 0 |
| 牛里脊 | 2 | 0 | 0 |
逐单元格手动演算:
T
F
=
3
,
I
D
F
=
0.41
⟹
3
×
0.41
=
1.23
TF=3,\\ IDF=0.41 \\implies 3 \\times 0.41 = \\boldsymbol{1.23}
TF=3, IDF=0.41⟹3×0.41=1.23
T
F
=
2
,
I
D
F
=
1.10
⟹
2
×
1.10
=
2.20
TF=2,\\ IDF=1.10 \\implies 2 \\times 1.10 = \\boldsymbol{2.20}
TF=2, IDF=1.10⟹2×1.10=2.20
T
F
=
3
,
I
D
F
=
0
⟹
3
×
0
=
0
TF=3,\\ IDF=0 \\implies 3 \\times 0 = \\boldsymbol{0}
TF=3, IDF=0⟹3×0=0(通用词权重清零)
最终生成TF‑IDF 加权词项‑文档矩阵:
| 川味 | 0 | 0 | 0 |
| 水煮牛肉 | 1.23 | 0.41 | 0 |
| 牛里脊 | 2.20 | 0 | 0 |
当用户输入查询语句时,我们对查询文本执行完全相同的分词、TF‑IDF计算,生成查询向量;再将查询向量和矩阵中每一列的文档向量计算相似度,按照相似度从高到低完成文档排序,最终返回检索结果。
5. TF-IDF 致命短板
TF-IDF 是传统稀疏检索的经典基线方案,依靠词频与全局词权重实现文档相关性打分,解决了基础命中打分、简易词频打分的核心缺陷。
但在实际检索场景中,原始 TF-IDF 算法存在两处致命短板,无法适配真实业务的检索需求:
- 词频无上限,分数容易虚高:关键词无限堆砌即可拉高得分,低质量刷词文档排名靠前,排序失真。
- 未做文档长度归一化:篇幅更长的文档天然拥有更多命中机会,打分对短而精炼的优质文档不公平。
正因 TF‑IDF 存在上述缺陷,工业界进一步演化出 BM25 算法,作为生产环境稀疏检索的标准实现。



