第四章 索引结构基础:倒排索引与B树

说到密文索引,很多人第一反应是「把B树搬过来,加密一下不就行了?」。嗯,我曾经也这么想,直到在项目中踩了坑才发现——倒排索引和B树,这两兄弟虽然都叫索引,但底层的数据组织方式完全是两套思路。今天咱们就掰开揉碎了聊聊。

4.1 B树:数据库的定海神针

B树是什么?说白了就是一种平衡的多路搜索树。它有个核心特性:每个节点可以存储多个键值对,并且保持有序。叶子节点在同一层,查询任何记录走的路径长度都差不多。

我个人习惯把B树想象成一个分层索引目录。根节点放几把「钥匙」,告诉你下一层去哪找;中间节点继续分叉;最后到叶子节点,数据就在那儿等着你。

B树的关键参数

参数 含义 典型值
阶数 (m) 每个节点最多能有多少个子节点 100~500(取决于页面大小)
高度 (h) 从根到叶子需要经过多少层 对于百万级数据,h ≤ 3
节点利用率 节点中实际存储的键数与最大容量之比 约 50%~70%

你想想看,一个三层的B树就能处理几百万条记录。为什么?因为每个节点可以装几百个键,分叉极多。我曾经用B树给一个明文数据库做索引,两千万条记录,树高才4层——每次查询最多读4个页面,速度飞快。

4.2 倒排索引:全文检索的灵魂

倒排索引就完全是另一回事了。它不关心键的顺序,它关心的是「某个词出现在哪些文档里」。

结构很简单:一个词典(Dictionary),每个词后面挂一个倒排列表(Posting List)。列表里存的是文档ID列表,可能还有位置、频率等信息。

举个例子:

文档1: "猫 喜欢 鱼"
文档2: "狗 喜欢 骨头"
文档3: "猫 讨厌 洗澡"

倒排索引:
"猫"   -> [1, 3]
"喜欢" -> [1, 2]
"鱼"   -> [1]
"狗"   -> [2]
"骨头" -> [2]
"讨厌" -> [3]
"洗澡" -> [3]

查询「猫 AND 鱼」怎么做?取出"猫"的列表 [1,3],取出"鱼"的列表 [1],求交集 → [1]。这就是倒排索引最擅长的——集合运算。

核心区别一句话总结:

B树是「值 → 位置」的映射,支持范围查询;倒排索引是「词 → 文档集合」的映射,支持多关键词的交、并、差运算。

4.3 密文索引面临的核心矛盾

把这两种结构搬到密文场景下,麻烦就来了。

B树依赖键的有序性才能做范围查询、快速定位。一旦加密,顺序被彻底打乱——除非你使用保序加密(OPE),但OPE有泄漏风险,我在项目中吃过亏。

倒排索引依赖词典的精确匹配和倒排列表的交集运算。密文状态下,你不能直接比较两个密文是否相等,也不能直接做位图交集——都需要可搜索加密(SSE)的辅助。

为什么不能简单地把B树的节点加密了事?因为密文不可比较。你拿着一个加密后的键,想去B树里查找,找不到,因为密文没有顺序可言。除非你额外维护一个比较用的辅助结构——这就引入了性能代价。

我曾经踩过的坑:

早期做密文B树时,我把每个节点整体加密存到磁盘。查询时先把整个节点读出来解密,再比较明文。单次查询复杂度是O(h),但每次IO都要加解密,吞吐量直接崩了。

4.4 两种索引在密文场景下的适用性对比

维度 B树 倒排索引
查询类型 精确、范围、前缀 关键词匹配、布尔查询
密文友好度 低(需要OPE或辅助结构) 中等(依赖SSE和位图)
数据更新 容易(原地更新) 困难(倒排列表重写代价高)
空间开销 低(约数据量的1.2~1.5倍) 高(倒排列表可能膨胀数倍)
典型适用 结构化记录检索 全文搜索、日志分析

这张表你看明白了吧?没有银弹。密文场景下,你需要根据业务查询类型决定用哪种结构,或者把两者结合起来。

4.5 核心知识点体系

为了让结构更直观,我画了一张框架图。它把本章的知识点串起来了——先认识两种索引,再理解它们在明文下的工作机制,最后分析密文移植的挑战和应对思路。

密文索引结构基础 — 知识体系 B树(有序索引) 平衡多路搜索树,节点存储键值对 倒排索引(无排序) 词典 + 倒排列表,面向词匹配 范围查询 O(log n) 复杂度 原地更新 插入删除灵活 集合运算 交并差高效 位图压缩 减少存储膨胀 密文场景的核心矛盾 加密后丢失顺序 / 无法直接比较 / 集合运算受限 保序加密 + 辅助比较结构 可搜索加密 密文位图 + 布隆过滤器 B树相关 倒排索引相关 本章知识脉络

4.6 我的一些实践建议

如果你刚接触密文索引,我建议按这个顺序理解:

  1. 先吃透明文B树和倒排索引的底层实现。 不理解明文数据的组织方式,密文优化就是空中楼阁。
  2. 然后想清楚你的业务查询类型。 如果是「某个字段在什么范围内」,走B树路线;如果是「包含某些关键词」,走倒排路线。
  3. 密文改造时,不要试图完美复制明文结构。 我曾经尝试把B树每个节点独立加密,结果维护比较序的辅助结构比索引本身还大——得不偿失。
  4. 多考虑混合策略。 比如用B树处理主键范围查询,用倒排索引处理多字段的布尔组合。

一个小窍门:

密文倒排索引的词典可以做确定性加密(相同词加密结果相同),这样你不用解密就能判断两个词是否相等。但要注意——这会泄漏词频信息。如果安全等级高,需要配合差分隐私或填充机制。

OK,这一章的核心就这些。倒排和B树,一个面向集合运算,一个面向有序搜索。到了密文世界,它们各自的弱点会暴露出来。但反过来想——正是因为不能直接拿来用,才需要我们去做优化,不是吗?