LlamaIndex 系列【18】关键词检索(Keyword Search):TF-IDF 算法

文章目录

  • [1. 算法介绍](#1. 算法介绍)
  • [2. 整体流程](#2. 整体流程)
    • [2.1 📦 阶段一:离线预处理](#2.1 📦 阶段一:离线预处理)
    • [2.2 🔍 阶段二:在线实时检索](#2.2 🔍 阶段二:在线实时检索)
  • [3. 核心概念](#3. 核心概念)
    • [3.1 系统词汇表](#3.1 系统词汇表)
    • [3.2 稀疏向量](#3.2 稀疏向量)
    • [3.3 文档-词项矩阵](#3.3 文档-词项矩阵)
  • [4. 打分算法迭代演进](#4. 打分算法迭代演进)
    • [4.1 版本一:简单命中计数打分](#4.1 版本一:简单命中计数打分)
    • [4.2 版本二:TF 原始词频打分](#4.2 版本二:TF 原始词频打分)
    • [4.3 版本三:TF‑IDF(词频‑逆文档频率)](#4.3 版本三:TF‑IDF(词频‑逆文档频率))
      • [步骤 1:计算 DF(文档频率)](#步骤 1:计算 DF(文档频率))
      • [步骤 2:权重反转](#步骤 2:权重反转)
      • [步骤 3:对数平滑得到标准 IDF](#步骤 3:对数平滑得到标准 IDF)
      • [步骤 4:TF‑IDF 加权计算](#步骤 4:TF‑IDF 加权计算)
    • [5. TF-IDF 致命短板](#5. TF-IDF 致命短板)

1. 算法介绍

关键词检索Keyword Search)属于信息检索技术的基础方法之一,是一种通过输入关键字获取文档信息的查询方式。

这种技术几十年来一直驱动着数据库和搜索引擎的检索。它的简单性和高效性,使其成为现代 RAG 系统检索的核心组成部分。

基本思路统计文档与查询重叠词数量,重叠越多原始分数越高,但不理解语义,只看字面词共现。

示例,当前有三个做菜相关的文档:

  • Doc1:做川味水煮牛肉,首选牛里脊,搭配豆芽莴笋打底。
  • Doc2:这家川味菜馆的水煮牛肉支持外卖,可以在家点单食用。
  • Doc3:这家川味老店生意火爆,很多食客会在家点麻辣火锅。

用户输入提问:

text 复制代码
怎么自制川味水煮牛肉?

输入会进行关键词拆分为:怎么、自制、川味、水煮牛肉,根据关键词三个文档都会被召回:

文档 文档真实语义 命中关键词 字面命中数量
Doc1 讲解自制水煮牛肉做法,匹配用户意图 川味、水煮牛肉 2
Doc2 介绍餐馆外卖服务,并非做菜教程 川味、水煮牛肉 2
Doc3 介绍自制麻辣火锅,与水煮牛肉无关 川味 1

其中 Doc1Doc2 字面命中数量一致,但语义相关性天差地别,简单的命中计数无法区分真实相关性。

2. 整体流程

TF‑IDF 的完整链路分为 知识库离线构建流程用户在线检索流程 两大阶段:

  1. 离线阶段(预处理) :对全部文档分词 → 构建全局词表 → 统计 TF / DF → 计算 IDF,生成 TF‑IDF 稀疏向量库
  2. 在线阶段(实时查询) :用户输入 Query → 分词 → 使用离线保存的 IDF 表计算 QueryTF‑IDF 稀疏向量 → 积分排序 → 返回 Top‑K 文档

2.1 📦 阶段一:离线预处理

一次性执行,知识库更新时重新跑:

  1. 原始文档输入:收集知识库全部非结构化文本。
  2. 文本清洗 :去除标点、特殊符号、过滤无意义停用词(的、是、怎么)。
  3. 分词:将连续句子切割成独立词语列表。
  4. 构建全局词汇表:合并所有文档词语,去重,给每个词分配唯一固定下标,保证所有向量维度对齐。
  5. 计算 TF(词频 Term Frequency):针对每一篇文档,统计每个词汇在本文档内出现多少次。
  6. 计算 DF(文档频率 Document Frequency) :统计整个知识库中,包含该词语的文档一共有多少篇。
  7. 计算 IDF(逆文档频率 Inverse Document Frequency)
    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 分值越低。
  8. 生成 TF‑IDF 加权向量
    T F ‑ I D F = T F × I D F TF‑IDF = TF × IDF TF‑IDF=TF×IDF
    每个词语最终权重 = 局部词频 × 全局稀有度权重
  9. 持久化存储 :保存所有文档 TF‑IDF 稀疏向量,以及全局 IDF 字典,供线上查询复用。

2.2 🔍 阶段二:在线实时检索

每次用户提问执行:

  1. 用户输入自然语言 Query
  2. Query 使用和文档完全一致的清洗、分词规则
  3. 统计 Query 内每个词汇的局部词频 TF
  4. 读取离线预计算的全局 IDF 字典,得到查询词语的加权分值。
  5. 通过倒排索引快速筛选出包含目标关键词的候选文档 ;对候选文档累加词语的 TF‑IDF权重作为最终相关性得分。
  6. 按相关性分数降序排序,截取前 K 个文档作为检索结果返回。

3. 核心概念

3.1 系统词汇表

系统词汇表:整个知识库提前固定好的、不变化的全局词语清单,它给每一个词语分配唯一固定下标,用来统一所有文档向量的维度。

把全部文档里所有不重复的词收集、去重,整理成一份全局词列表,这份列表就是系统词汇表

上面的 Doc1Doc2Doc3 三个做菜文档,收集去重后的系统词汇表(固定顺序,全局唯一):

下标 词语
0 川味
1 水煮牛肉
2 牛里脊
3 豆芽
4 莴笋
5 菜馆
6 外卖
7 麻辣火锅

3.2 稀疏向量

为了让知识库能够被检索,每个文档都会生成一个稀疏向量。

这些词频会被存储在一个向量中,这个向量为系统词汇表中的每个词都分配一个固定位置,向量中的每个数字,表示该词语在文本里出现的次数。

上面那套词汇表规则中,每个文档词频对应的向量为:

  • Doc11, 1, 1, 1, 1, 0, 0, 0
  • Doc21, 1, 0, 0, 0, 1, 1, 0
  • Doc31, 0, 0, 0, 0, 0, 0, 1

向量的维度很高,可能有数万个位置,由于绝大多数位置存放的值都是 0 ,这类向量叫做稀疏向量Sparse Vectors)。

稠密向量Dense Vector)对比:

对比项 TF‑IDF 向量(稀疏) Embedding嵌入向量(稠密)
生成方式 分词+统计公式,无神经网络 大模型/预训练Encoder推理输出
向量维度 等于词表大小(上万~几十万维) 固定小维度(512/768/1024)
向量特征 大量0,稀疏 数值连续非0,稠密
语义能力 仅字面匹配,不理解语义 承载语义,支持同义模糊匹配
相似度计算 余弦/点积 余弦相似度
检索定位 稀疏检索(关键词召回) 稠密检索(语义召回)

3.3 文档-词项矩阵

每一篇文档生成稀疏向量后,全部向量组合形成二维网格结构 ,这个表格叫文档-词项矩阵Document-Term Matrix)。

结构定义:

  • 行:词项(系统词汇表中)
  • 列:单篇文档

关于单元格的取值,可以有多种形式,比如:

  • One‑Hot 形式:1 代表词语在该文档出现,0 代表未出现,只标记存在与否,不关心词汇出现多少次。
  • TF词频)形式:单元格填入该词在文档中的实际出现次数。数值越大,说明这个词在当前文档里反复出现,主题关联性更强。

上面的 Doc1Doc2Doc3 词项‑文档矩阵One‑Hot 形式):

词项\文档 Doc1 Doc2 Doc3
川味 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 原始词频打分

一种简易优化方案:文档中每出现一次关键词,就累加一次分值。

假设三篇文档内部词汇出现频次如下:

关键词 Doc1词频 Doc2词频 Doc3词频
自制 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 Jones1972 年提出,后来与 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=包含该词的文档数量总文档数量

代入案例演算:

  1. 川味: D F = 1.0 DF=1.0 DF=1.0,中间权重 1 1.0 = 1 \displaystyle \frac{1}{1.0}=1 1.01=1
  2. 水煮牛肉: 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
  3. 牛里脊: D F ≈ 0.33 DF≈0.33 DF≈0.33,中间权重 1 0.33 ≈ 3 \displaystyle \frac{1}{0.33}≈3 0.331≈3
词项 DF 中间权重 1 D F \boldsymbol{\dfrac{1}{DF}} DF1 变化效果
川味 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(包含该词的文档数总文档数)

案例计算:

  1. 川味: log ⁡ ( 1 ) = 0 \log(1)=0 log(1)=0
  2. 水煮牛肉: log ⁡ ( 1.5 ) ≈ 0.41 \log(1.5)≈0.41 log(1.5)≈0.41
  3. 牛里脊: log ⁡ ( 3 ) ≈ 1.10 \log(3)≈1.10 log(3)≈1.10

对数不会改变大小关系:稀有词依然分数更高,只是把巨大的差值压缩到一个合理的小数区间。全局高频词最终权重归零,不再干扰检索打分。

词项 命中文档数 DF N 命中数 \boldsymbol{\dfrac{N}{命中数}} 命中数N(倒数反转) IDF(对数平滑)
川味 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 原始词项‑文档矩阵

词项 Doc1(TF) Doc2(TF) Doc3(TF)
川味 3 1 2
水煮牛肉 3 1 0
牛里脊 2 0 0

逐单元格手动演算:

  1. Doc1 - 水煮牛肉: 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
  2. Doc1 - 牛里脊: 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
  3. Doc1 - 川味: 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 加权词项‑文档矩阵

词项 \ 文档 Doc1 Doc2 Doc3
川味 0 0 0
水煮牛肉 1.23 0.41 0
牛里脊 2.20 0 0

当用户输入查询语句时,我们对查询文本执行完全相同的分词、TF‑IDF计算,生成查询向量;再将查询向量和矩阵中每一列的文档向量计算相似度,按照相似度从高到低完成文档排序,最终返回检索结果。

5. TF-IDF 致命短板

TF-IDF 是传统稀疏检索的经典基线方案,依靠词频与全局词权重实现文档相关性打分,解决了基础命中打分、简易词频打分的核心缺陷。

但在实际检索场景中,原始 TF-IDF 算法存在两处致命短板,无法适配真实业务的检索需求:

  • 词频无上限,分数容易虚高:关键词无限堆砌即可拉高得分,低质量刷词文档排名靠前,排序失真。
  • 未做文档长度归一化:篇幅更长的文档天然拥有更多命中机会,打分对短而精炼的优质文档不公平。

正因 TF‑IDF 存在上述缺陷,工业界进一步演化出 BM25 算法,作为生产环境稀疏检索的标准实现。

相关推荐
梦想很大很大1 小时前
从 Scope State 到 Guardrails:Workrun 如何为 Agent 工作流建立安全边界
安全·agent·workflow
luckystar513~1 小时前
Hermes 实战 :调度——cron 6:00 无人值守跑日报
人工智能·agent·智能体·hermes·实战专栏
ddshub_cc2 小时前
Claude Fable 5.1 Prompt Engineering:长程任务与编程 Agent 怎么写提示
ai·prompt·api·ai编程·claude·claude code·fable 5.1
Csvn2 小时前
第 15 章 规划 Planning
人工智能·aigc·agent
Sherotree2 小时前
结构化输出 / JSON Mode 入门
ai·api·结构化输出·json mode
William一直在路上2 小时前
MCP 规范版本对比:2025-11-25 vs 2026-07-28
学习·ai·llm
GHL2842710902 小时前
codex操作excel学习
学习·ai·word·excel
学习星球2 小时前
AI 一句话生成 3D 游戏世界:腾讯 HY-World 2.0 开源深度解析与本地实战
开发语言·人工智能·游戏·3d·ai·课程设计·ai编程
DO_Community2 小时前
Baseten vs DigitalOcean、RunPod:7 个 AI 模型部署平台横向对比
人工智能·llm·aigc·agent·ai编程