搜索与倒排索引基础

数据库的 LIKE '%关键词%' 只能全表扫描,一旦需要分词、相关度排序、高亮与聚合,就该考虑搜索引擎。搜索引擎的核心结构是倒排索引:从“词”找到“包含它的文档”。本章讲清正排与倒排的区别、分词与倒排表结构、相关度打分的基本概念,以及何时该用搜索引擎。

正排索引 vs 倒排索引

维度正排索引倒排索引
结构文档 id → 文档内容或字段词 → 包含该词的文档列表
查询方式按 id 取文档按词找文档
典型用途详情页、按主键查询全文检索、多条件筛选
检索效率关键词检索需要遍历全部文档直接命中词表,效率与文档总量弱相关

一句话记忆:正排是“知道 id 找内容”,倒排是“知道词找 id”。

分词与分析器

文本要先被拆成词条才能建立倒排。分析器通常包含三步:

原文:MySQL 8.0 性能优化实战
├─ 字符过滤:去掉 HTML 标签与特殊符号
├─ 分词:MySQL / 8.0 / 性能 / 优化 / 实战
└─ 词条归一化:转小写、去停用词、同义词折叠

中文分词是重点:英文按空格切分即可,中文没有天然分隔符,需要专门的分词器(基于词典分词或按单字切分)。索引阶段与查询阶段必须使用同一个分析器,否则索引里的词和查询的词对不上,检索结果会异常稀少。

倒排表结构

倒排索引由两部分组成:词典(全部词条及指向倒排链的指针)与倒排链(该词出现的文档列表及位置信息)。

词典(Term Dictionary)       倒排链(Posting List)
"性能"  ───────────────────→ doc1(pos=3), doc5(pos=7), doc9(pos=1)
"优化"  ───────────────────→ doc1(pos=4), doc9(pos=2)
"实战"  ───────────────────→ doc7(pos=2)

倒排链中除了文档 id,还可以存词频与位置:词频用于打分,位置用于短语查询(例如“性能优化”要求两词相邻)。

词典需要按序存储以支持二分或前缀查找,倒排链则需要压缩:

压缩手段思路
差值编码存文档 id 之间的差值而非绝对值,数值变小更易压缩
位图文档 id 稠密时用 bit 表示“是否包含”,多词求交可位运算
跳跃指针在倒排链中加跳步,加速多词求交
分块把倒排链分块,块内再压缩,便于随机定位

相关度打分:TF-IDF 与 BM25

命中多个文档后需要排序,打分解决“谁更相关”:

  • TF(词频):词在文档中出现越多通常越相关,但增长需要收敛,避免靠堆词刷分。
  • IDF(逆文档频率):词越罕见越有区分度,权重越高(“的”这类词几乎没权重)。
  • TF-IDF:两者相乘,直观但未考虑文档长度。
  • BM25:在 TF-IDF 基础上引入词频饱和与文档长度归一化,是多数搜索引擎的常用打分函数。

工程上不必手推公式,但要知道打分参数(词频饱和系数、字段权重)可调,调优时应使用真实查询日志构造评测集,而不是凭感觉。

搜索引擎的定位

以 Elasticsearch 为例,几个必须理解的概念:

概念含义
文档检索的基本单位,对应一条 JSON 记录
索引文档的集合,类似数据库中的“表”
分片索引的水平切分,决定并行度与单分片容量上限;分片数在建索引时确定,后期调整代价高
副本分片的拷贝,用于容错与分担读流量
近实时写入后需经过刷新才可被搜索到,存在秒级延迟,并非即时可见

因此搜索引擎不能当强一致的数据库使用:写入后立刻查询可能查不到,需要主动刷新或改为按主键直查。

什么时候用搜索引擎

-- 可以接受:前缀匹配,能走索引
SELECT id, name FROM goods WHERE name LIKE '机械键盘%';

-- 不建议:前导通配符,必然全表扫描
SELECT id, name FROM goods WHERE name LIKE '%键盘%';
需求推荐方案
按主键或索引列精确过滤关系型数据库
前缀匹配且数据量小数据库 LIKE '关键词%'
中文分词、多字段相关度排序搜索引擎
高亮、同义词、拼写纠错搜索引擎
强一致的交易数据数据库(搜索引擎只做检索副本)

常见组合是“数据库存真相、搜索引擎建索引”,通过消息队列同步变更,接受秒级延迟。

小结:倒排索引把“找文档”变成“找词”,所以全文检索的代价与文档总量弱相关;理解分词、倒排链压缩与 BM25 打分是读懂搜索引擎的基础,而选型的关键在于区分“精确查询”与“相关度检索”两类需求。

笔记加载中…