当一张表有明确字段时,我们可以用等值、范围和连接条件精确描述答案。文本却不一样:同一个意思可能有多种写法,用户通常只输入几个词,而且符合条件的文档往往成千上万。检索系统因此要同时回答两个问题:哪些文档可能有用,以及哪些文档应该排在前面。
这篇内容从一条文档进入系统开始,依次拆开文本处理、倒排索引、查询执行、相关性评分、质量评估和权限过滤。你会看到,搜索并不是对全文逐篇扫描,也不是只靠一个“智能模型”直接给答案;它是一条由多个可检查环节组成的工程链路。
信息检索主要处理没有固定字段结构的文本。一个网页、一封邮件、一份技术文档,甚至数据库中一个长文本字段,都可以视为一篇文档。用户提交若干词项后,系统从文档集合中找出候选项,再按估计相关性降序返回少量结果。
这与精确查询有一个根本差别。执行 WHERE order_id = 42 时,记录要么满足条件,要么不满足;搜索“数据库故障恢复”时,一篇只出现“日志重做”的文章也可能有用。检索结果因此通常是一个排序列表,而不是无序的真值集合。
完整链路可以分成离线与在线两部分。离线阶段采集文档、清洗文本并构建索引;在线阶段理解查询、读取倒排表、召回候选、计算相关性、执行权限过滤,最后展示前 个结果。索引把大量预计算工作提前完成,在线请求才不必扫描每篇原文。

“包含查询词”只是候选条件,不等于“最相关”。召回阶段尽量避免漏掉可能有用的文档,排序阶段再把更可能满足需求的结果放到前面。把这两个目标分开,才能解释系统为什么既需要倒排索引,也需要相关性模型。
索引的最小单位不是屏幕上看到的字符,而是经过处理后的词项。同一套处理必须同时用于文档和查询,否则文档里的“Database”和查询里的“database”可能落入两个不同词项,明明相关却无法相遇。
典型处理管线包括下面几步:

以“数据库系统支持数据库管理”为例,若从 1 开始编号,词项“数据库”可能对应位置 ,“系统”对应位置 。只记录词频可以做粗粒度排序;保留位置后,系统还能判断“数据库 系统”是否相邻出现。
正排表示从文档出发列出其中的词项,倒排索引则反过来:从词项出发,列出包含它的文档。词典负责把词项映射到倒排表;倒排表通常按文档编号排序,每个文档项还可以保存词频、位置、字段和其他统计量。

设“数据库”的倒排表是 ,“系统”的倒排表是 。查询要求两个词都出现时,只需并行扫描两个有序列表,得到交集 。复杂度与参与合并的列表长度有关,而不是与全部文档数直接相等。
倒排项可以写成如下逻辑结构:
词典可能放在内存中的哈希表或搜索树里,较长的倒排表则顺序存储。对高频词,列表会很长;对稀有词,列表很短。执行多词 AND 查询时,先从最短列表开始求交,通常能更早缩小候选集合。
位置索引比只存文档编号更占空间,但它换来了短语、邻近、高亮和更细的相关性特征。是否保存位置不是统一答案,应由查询能力和存储预算共同决定。
布尔查询把倒排表当作集合:AND 对应交集,OR 对应并集,NOT 对应相对于允许文档全集的差集。实际系统还会支持“至少命中 个词”、字段限定和括号优先级。这里的关键是先定义清楚语义,再选择合并算法。
短语查询需要位置索引。查询“数据库 系统”时,系统先找同时包含两个词的文档,再检查是否存在位置 ,使“数据库”出现在 、“系统”出现在 。若查询允许两个词之间最多隔三个词,位置条件可以放宽为距离不超过指定窗口。

下面的实验包含三篇小文档。你可以改变查询词和合并方式,观察倒排表如何生成候选;打开“要求相邻”后,系统会继续用位置判断短语。
候选文档可能很多,我们需要估计一篇文档与查询的相关程度。最直接的信号是词项在文档中出现的次数,但原始次数容易偏向长文档,而且从 1 次增加到 2 次带来的信息,通常大于从 50 次增加到 51 次。
一种带长度归一和对数衰减的词频写法是:
其中 是词项 在文档 中出现的次数, 是文档中的词项总数。不同系统会选择不同的 TF 变体,但目标一致:增加出现次数应提高权重,同时不能让长文档凭长度占尽优势。
只看 TF 仍然不够。“系统”可能出现在几乎所有技术文档中,“两阶段锁”只出现在少数文档里。后者更能区分主题。逆文档频率用包含词项的文档数 衡量这种稀有度。工程中常见的平滑形式是:
是文档总数。词项出现在越多文档中,IDF 越小。最终词项权重可以取 TF 与 IDF 的乘积,多词查询则组合各词项贡献:
允许查询侧表达不同词的重要程度。字段权重也可以进入计算,例如标题中的一次命中乘以高于正文的系数。停用词的 IDF 接近最低值,往往没有区分能力,因此可以从普通关键词索引中省略;但短语检索仍需谨慎处理。
把词典中的每个词项看成一个维度,一篇文档就可以表示为 TF-IDF 权重向量,查询也可以用同样方式表示。两个向量越接近,说明它们在高权重词项上的分布越相似。
余弦相似度用向量夹角衡量方向的一致程度:
分母对向量长度做归一化,因此长文档不会仅因包含更多词就必然得高分。若权重均非负,结果通常在 0 到 1 之间;越接近 1,方向越相似。余弦相似度并不理解事实真伪,它只度量当前特征空间中的接近程度。
下面的实验使用四篇固定长度和词频的文档。勾选查询词后,程序按平滑 IDF、对数 TF 和余弦相似度重新排序。观察稀有词如何改变名次。
TF-IDF 是清楚、可解释的基础,但真实排序通常会组合多种信号。词项是否命中标题、多个查询词是否靠近、文档是否新鲜、页面是否被高质量页面链接、用户是否经常在类似查询下选择该结果,都可能提供额外信息。

链接信号提供与当前查询相对独立的静态重要性。一个页面被许多重要页面指向,通常比只被少量低质量页面指向更有权威性。迭代式链接评分可写成:
是从页面 沿链接走到页面 的概率, 是随机跳转概率。这个分数与具体查询无关,因此不能单独代替内容相关性;常见做法是把它与词项得分、锚文本、点击或质量信号组合。
排序还要注意两个边界。第一,行为信号可能带来位置偏差:排在前面的结果天然更容易被点击,不能把点击直接当作绝对相关。第二,权限不是相关性特征。没有权限的文档即使分数最高也必须被过滤,而不是“扣一点分后仍可能返回”。
大多数用户只看前几项,系统通常直接维护一个大小为 的候选堆,或使用分块上界跳过不可能进入前 的文档。这样可以得到 Top-k,而不必给全部候选完成精确排序。
用户输入可能有错别字、漏字、同音替换或键盘邻键错误。严格按词项查找时,一个不存在于词典中的词会得到空倒排表。纠错模块通常先生成少量候选词,再结合词典频率和上下文给候选排序。
编辑距离把一个字符串变成另一个字符串所需的插入、删除和替换次数作为差异度量。例如,把“数椐库”改成“数据库”只需一次替换。为了避免对整个词典逐词计算,可以使用前缀树、删除词典、字符 n-gram 或 BK 树缩小候选范围。

候选生成之后,还要判断“该不该改”。一个低频专业词可能是正确输入,热门词也未必符合当前语境。稳妥的策略是综合:
模糊查询与自动纠错也应有边界。前缀、通配符或编辑距离放得过宽,会迅速扩大候选词和倒排表数量,既降低精度,也增加延迟。因此系统通常限制最大编辑距离、候选数和允许展开的词项数。
检索质量不能只看返回了多少结果。设检出的相关文档数为 ,检出的不相关文档数为 ,漏掉的相关文档数为 。查准率和查全率分别是:
查准率回答“返回的结果中有多少真的相关”,查全率回答“所有相关文档中找回了多少”。提高判定阈值常会减少误报、提高查准率,却也可能漏掉边缘相关文档、降低查全率。二者的调和平均是:

搜索结果有顺序,所以还要看相关文档出现得是否足够早。Precision@ 和 Recall@ 只评估前 个结果。平均准确率 AP 在每个相关结果出现的位置计算 Precision@,再对这些值求平均;MAP 是多个查询 AP 的平均。若相关性有“高度相关、部分相关、不相关”等等级,NDCG 会按位置折损收益,并用理想排序归一化,更适合分级标注。
评估必须先定义标注集合与查询集合。只用系统已经找回的结果做标注,会看不见真正的漏检项;只测试热门查询,也无法反映长尾输入。离线指标适合稳定比较版本,上线后还要结合延迟、零结果率和经过偏差校正的交互信号。
下面拖动阈值,观察同一组带相关性标注的文档如何在查准率和查全率之间移动。
文档持续新增和修改时,不能每来一篇就重写整个大索引。常见做法是在内存中维护一个小的可变段,达到阈值后刷成不可变磁盘段;查询同时读取多个段,后台再把小段合并成大段。删除可以先写删除标记,在段合并时真正回收空间。
倒排表里的文档编号递增,可以存相邻编号之差。例如 转成差值 ,小整数再用可变字节编码或位级编码压缩。词典还可以用前缀共享减少重复字符串。压缩不仅节省磁盘,较少的读取字节也可能提高查询速度;代价是解码需要 CPU,更新策略也更复杂。

企业检索还必须执行安全裁剪。每篇文档可带访问控制列表、租户编号或可见范围,查询得到的候选集合要与当前用户的允许集合求交。过滤应贯穿召回、缓存、摘要生成和结果计数,不能只在页面展示前隐藏标题,否则总数、缓存键或高亮片段仍可能泄露文档存在性。
多租户系统常把租户条件尽量前推到索引分片或倒排表层。权限变化频繁时,需要在“重新写入索引”和“查询时读取最新权限”之间取舍:前者查询快但更新成本高,后者一致性及时但每次请求多一次过滤成本。
权限过滤不是页面层的装饰。只把无权结果从最终列表删掉,仍可能通过候选数量、缓存、摘要或耗时差异泄露信息。系统必须保证索引查询和结果物化的每个可观察环节都遵守相同访问边界。
搜索并不一定独立于数据库。商品、工单或论文通常既有标题、正文等文本,也有状态、时间、部门和价格等结构化字段。稳妥的执行方式是让倒排索引负责文本召回,让数据库或列式过滤结构负责精确条件,再对两个候选集合求交。例如“近一年、状态已解决、包含死锁诊断”的查询同时需要时间范围、枚举条件和文本相关性。
当用户不知道表结构时,关键词也可以用于结构化数据探索。可以把元组看成节点、外键看成边:关键词先命中若干元组,再寻找连接这些元组的短路径,并按路径长度、边权和节点重要性排序。它适合临时浏览,但答案含义可能不唯一,不能替代语义明确的 SQL。
知识图谱还能为文本中的实体提供稳定标识。人名、机构名或产品简称在不同文档里可能同名,实体链接把具体提及连到唯一节点。查询可同时利用文档中的句子和图中的关系补足信息,但要保留命中证据,让用户知道结果来自哪段文本或哪条结构化关系。
一条可上线的检索链路可以按下面的顺序检查:
先定义文档边界、字段、语言和权限模型,再确定分词、规范化和位置记录方式。索引与查询必须复用同一套词项处理版本。
为词项构建有序倒排表,并按需要保存词频、字段、位置和字符偏移。用分段写入、合并和删除标记处理持续更新。
查询先经过同样的文本处理,再执行布尔、短语、邻近或模糊展开。优先读取较短倒排表并尽早求交,控制候选规模。
对有权限的候选计算 TF-IDF、余弦相似度、字段命中、邻近和权威等信号,直接维护 Top-k,并保留可解释的命中特征。
检索系统的可维护性来自这些边界:词项处理有版本,倒排项有明确语义,排序信号可以单独观测,评估集合能够重复运行,权限条件不能被绕过。做到这些,模型和算法即使继续变化,整条链路仍然可解释、可回归、可安全更新。
用固定查询集和相关性标注比较 Precision@K、Recall@K、MAP 或 NDCG,同时检查延迟、索引新鲜度、零结果率和权限一致性。