容量型磁盘索引(DiskANN)
当向量数据集规模超过可用内存时,HNSW、IVF_FLAT 等内存索引受内存容量限制,难以同时满足性能与成本要求。DiskANN 将索引数据下沉至磁盘,在数据规模超出内存容量的情况下仍可提供较高的搜索精度与查询性能,适用于数十亿级及以上规模的向量检索场景。
限制说明
项 | 说明 |
索引启用方式 | 计算节点的CU 类型为容量型的集群默认启用 DiskANN;其他实例可在创建索引时显式指定索引类型为 |
部署模式版本要求 | 磁盘模式要求阿里云 Milvus 集群版本为 2.6.18 及以上;2.6.3 版本仅支持性能模式。 |
工作原理
DiskANN 结合 Vamana 图与 RaBitQ 量化两项技术实现磁盘上的高效向量搜索。
Vamana 图
Vamana 图是 DiskANN 基于磁盘策略的核心结构。与 HNSW 的多层结构不同,Vamana 采用单层稀疏图,通过两轮剪枝构图,在保持图连通性的同时引入更多长程边,减少搜索收敛所需的跳数。
构建过程如下:
初始随机连接:每个向量作为图中一个节点,节点之间初始随机连接形成密集网络,通常每个节点初始约 500 条边,以保证连通性。
两轮剪枝优化:剪除多余边,根据节点距离剔除低质量连接,优先保留高质量边,每个节点的最大边数由
MaxDegree限制;引入长程边,连接向量空间中相距较远的数据点形成跳转捷径,加快图上导航速度,构图时邻接搜索的广度由SearchListSize决定。
开源 DiskANN 将每个节点的邻居列表与其全精度向量存放在同一磁盘扇区,搜索时通过一次磁盘读取同时获得邻居关系与原始向量,实现隐式重排,但整个搜索过程涉及大量串行磁盘 I/O。阿里云 Milvus 将 Vamana 图索引在内存中重新组织,使搜索过程不产生磁盘 I/O,仅在最后的 Rerank 阶段从磁盘读取原始向量。
RaBitQ 量化
RaBitQ(Random Bit Quantization)将向量归一化后映射到超立方体的顶点上,每一维仅需 1 bit 表示,从而压缩存储开销并加速向量间的近似距离计算。
高维空间中随机向量之间的角度高度集中,量化到超立方体顶点的误差以 O(1/√d) 的速率收敛,因此维度越高、量化误差越小。在 768 维空间中,1 bit 量化的误差已经很小。阿里云 Milvus 在标准 1-bit RaBitQ 基础上采用 4-bit 扩展模式,每一维使用 4 bit 编码残差信息,以平衡压缩比与精度。
启用 DiskANN 索引
步骤一:创建容量型集群
创建阿里云 Milvus 实例时,将计算节点的CU 类型设置为容量型。集群创建完成后无需额外配置,即默认使用 DiskANN RaBitQ 索引类型;创建 Collection 时若索引类型配置为 AUTOINDEX,系统自动匹配 DiskANN 作为底层索引实现。
创建实例的具体操作,请参见快速创建Milvus实例。
使用 AUTOINDEX 时,describe_index 返回的索引类型仍为 AUTOINDEX,不显示自动匹配后的底层索引。如需确认实际生效的索引类型,可查询 Segment 级信息,index_name 为 DISKANN 即表示已匹配 DiskANN:
from pymilvus import connections, utility
connections.connect(uri="http://<endpoint>:19530", token="<user>:<password>")
for seg in utility.get_query_segment_info("<collection_name>"):
print(seg.segmentID, seg.num_rows, seg.index_name)步骤二:选择部署模式
同一份 DiskANN RaBitQ 索引支持两种部署模式,可根据业务诉求选择加载与搜索方式:
部署模式 | 加载行为 | 适用场景 |
性能模式(默认) | Vamana 图与 RaBitQ 量化编码均加载至内存 | 追求高 QPS 与低延迟的在线检索场景 |
磁盘模式 | Vamana 图存放在磁盘,仅 RaBitQ 编码加载至内存 | 对成本敏感,可接受一定 QPS 下降与延迟增加的场景 |
若无明确的成本压缩需求,建议保持默认的性能模式;内存成本是主要约束且业务可接受查询性能下降时,再切换为磁盘模式。磁盘模式要求集群版本为 2.6.18 及以上。
步骤三:规划内存与机型
按以下公式计算理论最小内存。实际内存占用略高于理论值,建议按理论值 × 1.5 预留资源。
性能模式:
内存大小 = 数据条数 × (维度 / 2 + 228) 字节磁盘模式:
内存大小 = 数据条数 × (维度 / 2) 字节以 1 亿条 768 维向量为例:
部署模式 | 理论内存 | 推荐内存(× 1.5) | 推荐机型 |
性能模式 | 1 亿 × (384 + 228) 字节 ≈ 57 GB | 约 85 GB | 2 台 16C64G 计算节点 |
磁盘模式 | 1 亿 × 384 字节 ≈ 36 GB | 约 54 GB | 1 台 16C64G 计算节点 |
步骤四:切换部署模式(可选)
默认使用性能模式。切换部署模式无需重建索引,仅在 load 阶段完成模式切换,流程为 release Collection、修改 Collection 属性、重新 load。
切换过程中 Collection 会被 release 并重新 load,期间该 Collection 的查询能力短暂不可用,建议在业务低峰期执行。
使用以下 Python 脚本完成切换:
from pymilvus import MilvusClient
CLUSTER_ENDPOINT = "http://xxx-internal.milvus.aliyuncs.com:19530"
TOKEN = "<user>:<password>"
COLLECTION_NAME = "<collection_name>"
def set_diskann_mode(mode: str):
client = MilvusClient(uri=CLUSTER_ENDPOINT, token=TOKEN, timeout=7200)
# 1. release collection
client.release_collection(COLLECTION_NAME)
# 2. 修改部署模式
client.alter_collection_properties(
COLLECTION_NAME,
properties={"diskann.rabitq_mode": mode},
)
# 3. 重新 load
client.load_collection(COLLECTION_NAME, timeout=7200)
client.close()
if __name__ == '__main__':
set_diskann_mode("disk") # 切换到磁盘模式
# set_diskann_mode("perf") # 切回性能模式参数说明:
参数 | 说明 |
| Milvus 实例的访问 Endpoint,可使用内网或公网地址,均需携带端口 19530。 |
| 访问凭证,格式为 |
| 目标 Collection 名称。 |
| 部署模式取值: |
切换完成后,可通过 describe_collection 返回的 properties 中的 diskann.rabitq_mode 确认当前模式。
参数配置
调整 DiskANN 参数可针对特定数据集与搜索负载,在速度、准确性与内存开销之间取得平衡。
当前引擎不会拒绝超出下述建议取值范围的参数。填入超出范围或不满足推荐关系的值不会返回错误,但可能导致召回率或查询性能异常,配置前需自行确认取值合理。
索引构建参数
以下参数影响索引的构建方式,调整会影响索引大小、构建时间与搜索质量。
参数 | 说明 | 取值 | 调优建议 |
| 控制 Vamana 图中每个数据点的最大连接(边)数。 | 整数,建议 [1, 512],默认 | 值越大图越密集,召回率越高,内存占用与构建时间也随之上升。多数场景建议设置在 [10, 100] 范围内。 |
| 索引构建过程中为每个节点搜索近邻的候选池大小。为添加到图中的每个节点维护包含 | 整数,建议不小于 | 值越大越有可能为每个节点找到真正的近邻,图质量与召回率越好,但索引构建时间显著增加。取值小于 |
搜索参数
以下参数影响搜索行为,调整会影响搜索速度、延迟与资源消耗。
参数 | 说明 | 取值 | 调优建议 |
| 搜索过程中遍历图时维护的候选池大小。 | 整数,默认 | 值越大找到真正近邻的几率越高(召回率越高),搜索延迟也会增加。建议设置为等于或略大于待检索的结果数量 |
| 搜索过程中是否使用原始向量进行精排。 | bool,默认 | 追求高 QPS 的场景可关闭精排,QPS 提升明显但召回率有所下降,在高 |
| 搜索过程提前终止阈值,连续 N 步无改善时停止搜索。 | 整数,建议 (0, 200],默认 | 值越大搜索越充分,召回率越高;值越小搜索早停越早,QPS 提升但召回率下降。 |
上述搜索参数需在数据量足够大时才体现效果。数据量较小的 Collection 会直接进行精确检索而不经过 ANN 索引,此时调整 search_list、use_refine、early_termination_threshold 对召回率与返回的 Distance 均无可观测影响,参数调优应在接近生产规模的数据集上验证。
Collection 的 Segment 数量过多会明显影响查询性能,建议定期通过管理页面或客户端 API 触发 Compaction,降低 Segment 数量。