跳转到内容

4.1 索引类型全景:从暴力搜索到磁盘索引

Milvus 有 8 种向量索引——不是选择困难,而是不同场景的最优解不同


这一节在讲什么?

pgvector 只有两种向量索引(IVFFlat 和 HNSW),Chroma 只有一种(自动 HNSW)。Milvus 提供了 8 种向量索引——从暴力搜索到内存索引到量化索引到磁盘索引再到 GPU 索引。这么多选择看起来让人头疼,但每种索引都有它最适合的场景。这一节我们要把 Milvus 的所有索引类型过一遍,帮你建立"什么场景用什么索引"的直觉。


为什么 Milvus 有这么多索引类型

答案很简单——不同场景的约束条件不同:

  • 数据量小时,暴力搜索就够了,不需要索引
  • 内存充足时,HNSW 最快、召回率最高
  • 内存有限时,需要量化索引(PQ/SQ)压缩向量
  • 数据量极大且内存有限时,需要磁盘索引(DiskANN)
  • 有 GPU 时,GPU 索引可以提供极致吞吐

没有一种索引能在所有场景下都是最优的——这就是 Milvus 提供多种索引的原因。


索引类型全景图

索引类型内存占用构建速度查询速度召回率适用场景
FLAT无需构建慢(暴力)100%< 10 万条,基准测试
IVFFlat中~高通用场景
HNSW很大很快内存充足、低延迟
IVF_PQ内存有限、大数据量
IVF_SQ8内存有限、精度可接受
SCANNGoogle 推荐算法
DiskANN磁盘为主数据量极大、内存有限
GPU_IVF_PQ极快GPU 服务器、极致吞吐

FLAT:暴力搜索

FLAT 不是真正的索引——它就是暴力搜索,逐条计算查询向量与所有向量的距离。它的召回率是 100%(因为检查了每一条数据),但速度最慢。

python
# 创建 FLAT 索引(实际上就是不建索引)
index_params = {
    "index_type": "FLAT",
    "metric_type": "COSINE",
    "params": {}
}
client.create_index(
    collection_name="documents",
    field_name="embedding",
    index_params=index_params
)

什么时候用 FLAT:数据量小于 10 万条时,暴力搜索的速度已经足够快(通常在 10ms 以内),不需要更复杂的索引。FLAT 也常用于基准测试——用 FLAT 的搜索结果作为"标准答案",来评估其他索引的召回率。


IVFFlat:倒排文件索引

IVFFlat 的原理我们在 pgvector 教程里已经详细讲过——它把向量空间划分为 K 个聚类区域,搜索时只扫描查询向量附近的几个区域。Milvus 的 IVFFlat 跟 pgvector 的 IVFFlat 原理相同,但参数名不同:

python
# 创建 IVFFlat 索引
index_params = {
    "index_type": "IVFFlat",
    "metric_type": "COSINE",
    "params": {"nlist": 1024}   # 聚类区域数量,类似 pgvector 的 lists
}
client.create_index(
    collection_name="documents",
    field_name="embedding",
    index_params=index_params
)

# 搜索时指定 nprobe
results = client.search(
    collection_name="documents",
    data=[[0.1] * 768],
    limit=5,
    search_params={
        "metric_type": "COSINE",
        "params": {"nprobe": 32}  # 搜索时扫描的区域数,类似 pgvector 的 probes
    }
)

IVFFlat 的局限跟 pgvector 一样——需要先有数据再建索引(聚类中心依赖数据分布),增量数据量大时需要重建索引。


HNSW:分层导航小世界图

HNSW 是目前最流行的向量索引——多层图结构,O(log N) 搜索复杂度,全内存驻留。Milvus 的 HNSW 跟 pgvector 的 HNSW 原理相同,参数名略有差异:

python
# 创建 HNSW 索引
index_params = {
    "index_type": "HNSW",
    "metric_type": "COSINE",
    "params": {
        "M": 16,              # 每层最大连接数(pgvector 叫 m)
        "efConstruction": 256  # 建索引时的搜索宽度(pgvector 叫 ef_construction)
    }
}
client.create_index(
    collection_name="documents",
    field_name="embedding",
    index_params=index_params
)

# 搜索时指定 ef
results = client.search(
    collection_name="documents",
    data=[[0.1] * 768],
    limit=5,
    search_params={
        "metric_type": "COSINE",
        "params": {"ef": 100}  # 搜索宽度(pgvector 叫 ef_search)
    }
)

HNSW 的内存估算公式:每条向量约 dim × 4 + M × 2 × 8 字节。768 维、M=16 的 HNSW 索引,每条向量约 3072 + 256 = 3328 字节,100 万条约 3.2 GB。


IVF_PQ / IVF_SQ8:量化索引

量化索引是 Milvus 相比 pgvector 和 Chroma 最核心的优势——它们通过压缩向量来大幅减少内存占用。下一节我们会详细讲量化原理,这里先看基本用法:

python
# IVF_PQ 索引——乘积量化,压缩比最高
index_params = {
    "index_type": "IVF_PQ",
    "metric_type": "COSINE",
    "params": {
        "nlist": 1024,
        "m": 48,           # PQ 的子空间数量(768 / 48 = 16 维/子空间)
        "nbits": 8         # 每个子空间的编码位数(默认 8)
    }
}

# IVF_SQ8 索引——标量量化,压缩比 4 倍
index_params = {
    "index_type": "IVF_SQ8",
    "metric_type": "COSINE",
    "params": {"nlist": 1024}
}

SCANN:Google 的 ANN 算法

SCANN(Scalable Nearest Neighbors)是 Google Research 提出的 ANN 算法,在多个基准测试中表现优异。Milvus 2.4+ 支持 SCANN 索引:

python
index_params = {
    "index_type": "SCANN",
    "metric_type": "COSINE",
    "params": {
        "nlist": 1024,
        "with_raw_data": True   # 是否保留原始向量(用于重排序)
    }
}

SCANN 的搜索参数跟 IVFFlat 类似,也是 nprobe。SCANN 的优势是在高召回率场景下比 IVFFlat 更快——但构建速度稍慢。


DiskANN:磁盘索引

DiskANN 是微软提出的磁盘向量索引——它把大部分数据放在磁盘上,只把少量元数据放在内存中,适合数据量极大但内存有限的场景:

python
index_params = {
    "index_type": "DISKANN",
    "metric_type": "COSINE",
    "params": {}   # DiskANN 不需要额外参数
}

DiskANN 的搜索参数是 search_list——控制搜索时的候选列表大小:

python
results = client.search(
    collection_name="documents",
    data=[[0.1] * 768],
    limit=5,
    search_params={
        "metric_type": "COSINE",
        "params": {"search_list": 100}
    }
)

DiskANN 的优势是内存占用极低——100 万条 768 维向量,DiskANN 只需要约 1 GB 内存(而 HNSW 需要约 3.5 GB)。代价是搜索延迟比 HNSW 高(因为需要读磁盘),但比暴力搜索快得多。


GPU_IVF_PQ:GPU 加速索引

如果你有 GPU 服务器,Milvus 支持 GPU 加速的 IVF_PQ 索引——利用 GPU 的大规模并行计算能力,搜索吞吐量可以提升 5~10 倍:

python
index_params = {
    "index_type": "GPU_IVF_PQ",
    "metric_type": "COSINE",
    "params": {
        "nlist": 1024,
        "m": 48,
        "nbits": 8
    }
}

GPU 索引需要 Milvus 启动时配置 GPU 资源,不是所有部署环境都支持。


索引创建流程

无论使用哪种索引,创建流程都是一样的:

python
# 第1步:创建索引(IndexNode 在后台构建)
client.create_index(
    collection_name="documents",
    field_name="embedding",
    index_params={
        "index_type": "HNSW",
        "metric_type": "COSINE",
        "params": {"M": 16, "efConstruction": 256}
    }
)

# 第2步:加载索引到 QueryNode 内存(必须!)
client.load_collection("documents")

# 第3步:搜索
results = client.search(
    collection_name="documents",
    data=[[0.1] * 768],
    limit=5,
    search_params={
        "metric_type": "COSINE",
        "params": {"ef": 100}
    }
)

常见误区:建了索引但忘记 load

这是 Milvus 初学者最常犯的错误——create_index() 只是把索引文件构建到对象存储中,并没有加载到 QueryNode 内存。你必须调用 load_collection()load_partitions() 把索引加载到内存才能搜索。如果忘记 load,搜索会报错或退化为暴力搜索。


小结

这一节我们概览了 Milvus 的 8 种向量索引:FLAT(暴力搜索)、IVFFlat(通用)、HNSW(最快最高召回率)、IVF_PQ/IVF_SQ8(量化压缩)、SCANN(Google 算法)、DiskANN(磁盘索引)、GPU_IVF_PQ(GPU 加速)。每种索引都有最适合的场景——没有银弹,只有最适合当前约束条件的选择。下一节我们深入 HNSW 索引的参数调优。

基于 MIT 许可发布