Appearance
索引创建与管理
索引概述
索引是 Milvus 实现高效向量搜索的核心机制。通过为向量字段创建索引,可以显著提升搜索速度,特别是在大规模数据集上。
为什么需要索引
- 加速搜索: 将时间复杂度从 O(n) 降低到接近 O(log n)
- 支持大规模数据: 处理十亿级向量数据
- 平衡精度与性能: 通过参数调整召回率和搜索速度
索引类型详解
FLAT(暴力搜索)
特点: 精确搜索,不损失精度,但速度最慢
适用场景:
- 数据量较小(< 100万)
- 需要 100% 召回率
- 作为基准测试
python
index_params = {
"index_type": "FLAT",
"metric_type": "L2", # 或 "IP", "COSINE"
"params": {}
}IVF_FLAT(倒排文件索引)
特点: 基于聚类的索引,平衡速度和精度
原理:
- 使用 K-means 将向量空间划分为 nlist 个聚类中心
- 搜索时先找到最近的 nprobe 个聚类中心
- 只在选中的聚类中搜索
python
index_params = {
"index_type": "IVF_FLAT",
"metric_type": "L2",
"params": {
"nlist": 128 # 聚类中心数,建议 4 × sqrt(n)
}
}
# 搜索参数
search_params = {
"metric_type": "L2",
"params": {
"nprobe": 8 # 搜索的聚类数,越大越精确但越慢
}
}参数说明:
nlist: 聚类中心数量,影响索引构建时间和搜索速度nprobe: 搜索时查询的聚类数,影响召回率
IVF_SQ8(标量量化索引)
特点: 使用 8-bit 量化压缩向量,节省存储空间
适用场景:
- 内存资源有限
- 可以容忍轻微精度损失
python
index_params = {
"index_type": "IVF_SQ8",
"metric_type": "L2",
"params": {
"nlist": 128
}
}IVF_PQ(乘积量化索引)
特点: 将向量分割成子向量分别量化,压缩率高
适用场景:
- 超大规模数据集
- 内存极度受限
python
index_params = {
"index_type": "IVF_PQ",
"metric_type": "L2",
"params": {
"nlist": 128,
"m": 8, # 子向量数量,必须整除向量维度
"nbits": 8 # 每个子向量的量化位数
}
}参数说明:
m: 子向量数量,通常设置为 dim/4 到 dim/8nbits: 量化位数,通常为 8
HNSW(分层可导航小世界图)
特点: 基于图的索引,搜索速度最快,召回率高
适用场景:
- 对搜索速度要求极高
- 需要高召回率
- 内存充足
python
index_params = {
"index_type": "HNSW",
"metric_type": "L2",
"params": {
"M": 16, # 每个节点的最大连接数
"efConstruction": 200 # 构建时的搜索范围
}
}
# 搜索参数
search_params = {
"metric_type": "L2",
"params": {
"ef": 64 # 搜索时的搜索范围,越大越精确
}
}参数说明:
M: 每个节点的最大连接数,建议 8-64,越大索引越大但越精确efConstruction: 构建时的搜索范围,建议 64-512ef: 搜索时的搜索范围,必须 >= topk
ANNOY(近似最近邻树)
特点: 基于树的索引,构建速度快
适用场景:
- 静态数据集
- 需要快速构建索引
python
index_params = {
"index_type": "ANNOY",
"metric_type": "L2",
"params": {
"n_trees": 8 # 树的数量
}
}
# 搜索参数
search_params = {
"metric_type": "L2",
"params": {
"search_k": -1 # 搜索的节点数,-1 表示 n_trees × topk
}
}DISKANN(磁盘索引)
特点: 专为磁盘存储优化的索引,支持超大规模数据
适用场景:
- 数据量超过内存容量
- 可以接受磁盘 I/O 延迟
python
index_params = {
"index_type": "DISKANN",
"metric_type": "L2",
"params": {}
}
# 搜索参数
search_params = {
"metric_type": "L2",
"params": {
"search_list": 16 # 候选列表大小
}
}SCANN(高速索引)
特点: 基于各向异性量化(Anisotropic Quantization)的索引,在速度和精度之间取得良好平衡,常用于高维向量的快速检索。
适用场景:
- 对召回率和速度都有较高要求
- 高维向量(如 768、1024 维 Embedding)
python
index_params = {
"index_type": "SCANN",
"metric_type": "L2",
"params": {
"nlist": 128, # 聚类中心数
"with_raw_data": True # 是否保留原始向量,提升精度
}
}
# 搜索参数
search_params = {
"metric_type": "L2",
"params": {
"nprobe": 8, # 搜索的聚类数
"reorder_k": 200 # 重排序候选数,越大越精确
}
}参数说明:
nlist: 聚类中心数量with_raw_data: 是否保存原始向量用于精排reorder_k: 重排序阶段的候选数量,建议 >= topk
GPU 索引系列
Milvus 支持基于 GPU 的向量索引,适合大规模数据和高并发场景。使用前需确保部署环境具备 GPU,并安装 GPU 版本的 pymilvus:
bash
pip install pymilvus[gpu]| 索引类型 | 算法 | 特点 | 适用场景 |
|---|---|---|---|
| GPU_CAGRA | 图索引(推荐) | 训练快、召回率高,最适合 GPU | 大规模数据、追求 GPU 性能 |
| GPU_IVF_FLAT | 倒排文件 | GPU 版 IVF_FLAT | 中等规模,需要精确聚类 |
| GPU_IVF_PQ | 乘积量化 | GPU 版 IVF_PQ,省显存 | 超大规模、显存受限 |
| GPU_BRUTE_FORCE | 暴力搜索 | GPU 并行精确搜索 | 小规模数据、需 100% 召回 |
GPU_CAGRA 代码示例:
python
index_params = {
"index_type": "GPU_CAGRA",
"metric_type": "L2",
"params": {
"intermediate_graph_degree": 64, # 构建中间图度数,影响召回率
"graph_degree": 32 # 最终图度数,影响搜索速度
}
}
# 搜索参数
search_params = {
"metric_type": "L2",
"params": {
"itopk_size": 128 # 搜索时保留的候选数
}
}二进制向量索引
二进制向量(BINARY_VECTOR)使用专门的索引类型,常用于指纹、哈希等场景,距离度量通常为汉明距离(HAMMING)或 Jaccard(JACCARD)。
| 索引类型 | 特点 | 适用场景 |
|---|---|---|
| BIN_FLAT | 暴力搜索,精确 | 小规模二进制向量 |
| BIN_IVF_FLAT | 倒排文件聚类 | 中大规模二进制向量 |
python
# BIN_FLAT 索引
index_params = {
"index_type": "BIN_FLAT",
"metric_type": "HAMMING", # 或 "JACCARD"
"params": {}
}
# BIN_IVF_FLAT 索引
index_params = {
"index_type": "BIN_IVF_FLAT",
"metric_type": "HAMMING",
"params": {
"nlist": 128
}
}
# 搜索参数
search_params = {
"metric_type": "HAMMING",
"params": {
"nprobe": 8
}
}创建索引
基本流程
python
from pymilvus import Collection
# 获取集合
collection = Collection("article_search")
# 定义索引参数
index_params = {
"index_type": "IVF_FLAT",
"metric_type": "L2",
"params": {
"nlist": 128
}
}
# 创建索引
collection.create_index(
field_name="article_vector", # 向量字段名
index_params=index_params
)
# 等待索引构建完成
collection.load()
print("索引创建成功!")完整示例
python
from pymilvus import connections, Collection, FieldSchema, CollectionSchema, DataType, utility
import random
def create_index_demo():
"""创建索引完整示例"""
# 连接 Milvus
connections.connect(host="localhost", port="19530")
# 创建测试集合
fields = [
FieldSchema(name="id", dtype=DataType.INT64, is_primary=True, auto_id=True),
FieldSchema(name="vector", dtype=DataType.FLOAT_VECTOR, dim=128)
]
schema = CollectionSchema(fields, "索引测试集合")
collection = Collection("index_demo", schema)
# 插入测试数据
print("插入测试数据...")
data = [{"vector": [random.random() for _ in range(128)]} for _ in range(10000)]
collection.insert(data)
# 创建 HNSW 索引
print("创建 HNSW 索引...")
index_params = {
"index_type": "HNSW",
"metric_type": "L2",
"params": {
"M": 16,
"efConstruction": 200
}
}
collection.create_index(
field_name="vector",
index_params=index_params,
index_name="vector_hnsw_index" # 指定索引名称
)
# 查看索引进度
print("等待索引构建完成...")
utility.wait_for_index_building_complete("index_demo")
# 加载集合并测试搜索
collection.load()
# 执行搜索
search_params = {
"metric_type": "L2",
"params": {"ef": 64}
}
results = collection.search(
data=[[random.random() for _ in range(128)]],
anns_field="vector",
param=search_params,
limit=10
)
print(f"搜索完成,找到 {len(results[0])} 个结果")
# 清理
utility.drop_collection("index_demo")
if __name__ == "__main__":
create_index_demo()索引管理
查看索引信息
python
# 获取索引信息
index_info = collection.indexes
for index in index_info:
print(f"索引名称: {index.index_name}")
print(f"字段: {index.field_name}")
print(f"参数: {index.params}")
# 获取特定字段的索引
index = collection.index("article_vector")
print(f"索引参数: {index.params}")删除索引
python
# 删除指定字段的索引
collection.drop_index(field_name="article_vector")
# 删除指定名称的索引
collection.drop_index(index_name="vector_hnsw_index")索引状态检查
python
from pymilvus import utility
# 检查索引构建进度
progress = utility.index_building_progress("article_search")
print(f"索引构建进度: {progress}")
# 等待索引构建完成
utility.wait_for_index_building_complete("article_search")
print("索引构建完成!")索引选择指南
根据数据规模选择
| 数据规模 | 推荐索引 | 说明 |
|---|---|---|
| < 100万 | FLAT / IVF_FLAT | 数据量小,精确搜索 |
| 100万 - 1000万 | IVF_FLAT / HNSW | 平衡速度和精度 |
| 1000万 - 1亿 | HNSW / IVF_PQ | 需要高性能索引 |
| > 1亿 | DISKANN / IVF_PQ | 超大规模数据 |
根据场景选择
| 场景 | 推荐索引 | 原因 |
|---|---|---|
| 需要 100% 召回率 | FLAT | 精确搜索 |
| 内存充足,追求速度 | HNSW | 最快的搜索速度 |
| 内存有限 | IVF_SQ8 / IVF_PQ | 压缩存储 |
| 数据超过内存 | DISKANN | 磁盘存储 |
| 频繁更新数据 | IVF_FLAT | 支持增量更新 |
参数调优建议
IVF 系列参数
python
# 小规模数据(< 100万)
{"nlist": 128, "nprobe": 8}
# 中等规模(100万 - 1000万)
{"nlist": 1024, "nprobe": 16}
# 大规模(> 1000万)
{"nlist": 4096, "nprobe": 64}HNSW 参数
python
# 追求速度
{"M": 8, "efConstruction": 64, "ef": 32}
# 平衡方案
{"M": 16, "efConstruction": 200, "ef": 64}
# 追求精度
{"M": 32, "efConstruction": 400, "ef": 128}性能优化建议
索引构建优化
- 批量插入后创建索引: 避免频繁重建索引
- 选择合适的 nlist: 通常设置为 4 × sqrt(n)
- 使用 GPU 加速: 大规模数据可考虑 GPU 索引
搜索优化
- 调整搜索参数: 根据召回率要求调整 nprobe/ef
- 使用分区: 减少搜索范围
- 批量搜索: 一次性搜索多个向量
python
# 批量搜索
query_vectors = [vector1, vector2, vector3, ...]
results = collection.search(
data=query_vectors,
anns_field="vector",
param=search_params,
limit=10
)常见问题
索引构建失败
python
# 检查数据量
if collection.num_entities < 1000:
print("数据量太小,建议使用 FLAT 索引")
# 检查向量维度
dim = collection.schema.fields[1].params.get("dim")
print(f"向量维度: {dim}")召回率过低
python
# 增加搜索参数
search_params = {
"metric_type": "L2",
"params": {
"nprobe": 128, # 增加搜索的聚类数
"ef": 256 # 增加搜索范围
}
}内存不足
python
# 使用量化索引
index_params = {
"index_type": "IVF_SQ8", # 或 IVF_PQ
"metric_type": "L2",
"params": {"nlist": 128}
}下一步
掌握索引管理后,你可以: