diskANN总结
diskANN
两种方式,内存式和硬盘式
内存式
构建阶段
-
PQ 压缩:将全量n条 D维向量分成 M个子空间,用 KMeans 得到每块码本,然后把每条向量量化成一个短码。
-
Vamana 图结构:在这些短码(或它们对应的低维浮点近似)上,用 Vamana 算法构建近邻图,存到主存中。
-
原始向量落盘:把全量的、未经压缩的 n×D 浮点向量,用 numpy.memmap 或者直接的二进制格式,存到 SSD/磁盘上。
查询阶段
-
Step A:压缩查询 & 图遍历
-
将查询向量 q 同样通过 PQ 编码成短码;
-
在主存的 Vamana 图上,用近邻走航(beam search)快速得到一批候选 ID(一般几百到几千个)。
-
-
Step B:候选重排 (Rerank)
-
用 numpy.memmap 从磁盘上随机读出这些候选 ID 对应的原始 D-维向量(因为它们是连续存储的,IO 性能较好);
-
计算它们与 q 的真实欧氏距离,对候选集做一次精确排序(Top-K 重排);
-
返回最终 Top-K 结果。
-
这样,虽然图遍历只用了 PQ 近似,但最终输出是基于原始高精度向量的距离,它能显著提高召回。
硬盘式(论文中给出的)
构建阶段
- 粗聚类与分片(Sharding)
- 对全量 n 条 D 维向量,用 MiniBatch‑KMeans 划分成 K 个簇中心(centroids);
- 每个点分配给a个最近的簇中心,形成“重叠分片”(overlapping shards),保证索引连通性。
- 则shard数量和K的关系: n u m = C K a num = C^a_K num=CKa(文中为a=2)
- PQ 训练与压缩
- 在全量原始浮点向量上训练 Product Quantization(PQ),学得 M 段码本;
- 对每条向量生成一个短码(例如 32 – 64 Bytes/PQ code),将所有短码及全局 PQ 码本加载到内存
- Vamana 图构建(全精度)
- 使用原始全精度浮点向量在每个 shard 内独立构建 Vamana 图;
- 将每个节点的邻居列表以二进制形式输出到 SSD 上(通常是一组 .ann 文件),并记录每个节点在文件中的偏移位置;
- 全局图合并
- 按节点 ID 顺序,把各 shard 的邻接列表文件合并成一个全局图索引文件,存于 SSD;
- 建立索引元数据(每个节点在全局文件中的偏移、邻居度数固定),供后续随机/顺序读取。
- 数据布局
- SSD 上:
- 全局 Vamana 图(邻接列表二进制)
- 全量原始浮点向量(按节点 ID 连续存储,便于顺序读)
- 内存中:
- PQ 码本 + 每点短码(n×Bytes)
- 全局图索引的简要元数据(偏移表、度数信息)
- SSD 上:
查询阶段
Step A: PQ 压缩查询 & Beam Search on SSD Graph
- 查询 PQ 编码
- 将查询向量 q 用内存中的 PQ 码本查表,得到短码或重构向量 q r e c q_{rec} qrec。
- 初始化候选池
- 从粗聚类中心或固定入口节点开始,将若干种子节点及其 PQ 距离 d ~ ( q , p ) \tilde d(q,p) d~(q,p) 放入大小上限为 L 的最小堆(heap)。
- Beam Search 循环
- 从 heap 中 pop 出最小的 W 个节点(仅在 heap ≤ L 范围内操作,无需遍历全库);
- 批量从 SSD 读这些节点的邻居列表(一次顺序 I/O),拿到它们的邻居 ID;
- 对每个新邻居,用其内存中的短码与 q 的 PQ 查表快速算出 d ~ ( q , r ) \tilde d(q,r) d~(q,r) (O(M) 查表加和);
- 将这些邻居连同距离 push 回 heap,并维持 heap 大小 ≤ L。
- 汇总候选
- 循环至达到最大迭代或 heap 不再更新,最后从 heap 中取出 Top‑R 候选 ID(几百到几千)。
Step B: 候选重排 (Rerank)
- 批量顺序读原始向量
- 用 numpy.memmap 或类似接口,一次性顺序加载这 R 个候选的全精度 D 维向量。
- 精确距离计算
- 对每个候选计算真实欧氏距离 ∥ q − x i ∥ \big\|q-x_i\big\| q−xi ,并排序取最终 Top‑K。
- 返回结果
- 输出重排后的 Top‑K ID 及距离。
要点小结
- 图构建:始终使用 全精度向量 确保索引质量最优;
- 在线查询:通过 内存中的 PQ 压缩向量 快速估距,决定从 SSD 上加载少量邻居;
- 非暴力遍历:Beam Search 只在候选池(≤ L)上做 pop/push,无需对全库做 O(n) 距离计算;
- 最后再用 SSD 上的全精度向量做精排,以最大程度提升召回。