RAG学习之【向量数据库】Milvus 从入门到精通:索引、检索、混合搜索一篇打通(RAG 必备)

【向量数据库】Milvus 从入门到精通:索引、检索、混合搜索一篇打通(RAG 必备)

💡 写在前面 :做 RAG、做推荐、做语义搜索,绕不开"向量数据库"这四个字。市面上的教程要么只讲 API 调用,要么只讲理论算法,真正能把部署 → Schema 设计 → 索引选型 → 搜索 → 混合检索 → 多模态一条龙讲透的少之又少。

这篇文章以 Milvus 为主线,把向量存储的核心知识系统梳理一遍,并配套 20 道高频面试题。无论你是刚入门 RAG,还是准备面试,都能直接收藏当手册用。📖


📑 文章目录

  • 一、先搞清楚:为什么需要向量数据库?
  • [二、Milvus 部署与连接](#二、Milvus 部署与连接)
  • [三、Collection / Partition / Alias 三剑客](#三、Collection / Partition / Alias 三剑客)
  • [四、Schema 设计:字段类型全家桶](#四、Schema 设计:字段类型全家桶)
  • [五、🔑 核心:五大索引类型怎么选?](#五、🔑 核心:五大索引类型怎么选?)
  • [六、搜索全家桶:从 ANN 到迭代搜索](#六、搜索全家桶:从 ANN 到迭代搜索)
  • 七、LlamaIndex:更高层的抽象
  • [八、🔥 重头戏:混合检索(Dense + Sparse)](#八、🔥 重头戏:混合检索(Dense + Sparse))
  • [九、BGE-M3 与 ColBERT:延迟交互到底牛在哪?](#九、BGE-M3 与 ColBERT:延迟交互到底牛在哪?)
  • 十、多模态检索:图文跨模态怎么玩
  • [十一、🎯 速查表合集](#十一、🎯 速查表合集)
  • [十二、20 道高频面试题(建议背诵)](#十二、20 道高频面试题(建议背诵))
  • 十三、总结

一、先搞清楚:为什么需要向量数据库?

很多新手会问:MySQL 不是已经能存数据了吗,为什么还要专门搞一个"向量数据库"?

答案的核心在于 "相似度检索" 这件事传统数据库做不了:

对比维度 关系型数据库(MySQL) 向量数据库(Milvus)
存储对象 结构化标量数据(数字、字符串) 高维向量 + 标量元数据
查询方式 精确匹配(WHEREJOIN) 相似度搜索(ANN 近似最近邻)
索引类型 B+Tree、Hash FLAT、IVF_FLAT、HNSW 等
距离度量 L2、IP、COSINE
典型场景 事务处理、业务 CRUD 语义搜索、推荐系统、RAG

🎯 一句话总结 :向量数据库解决的是高维空间中的相似度检索问题。传统数据库找的是"等于",向量数据库找的是"像不像"。

KNN vs ANN:为什么不总是精确搜索?

  • KNN(精确搜索) :遍历所有向量找真正的 Top-K,时间复杂度 O(n)
  • ANN(近似最近邻) :通过索引结构在亚线性时间内找到近似 Top-K

实际场景中,向量本身就是模型的近似表示,追求 100% 精确匹配意义不大,95%+ 的召回率通常已经完全够用,但速度能提升好几个数量级。


二、Milvus 部署与连接

Milvus Standalone 通过 Docker Compose 部署,包含三个核心服务:

  • etcd:元数据存储(端口 2379)
  • minio:对象存储(端口 9000/9001)
  • milvus-standalone:向量数据库服务(端口 19530/9091)
yaml 复制代码
# docker-compose.yml 核心配置
image: milvusdb/milvus:v2.5.10
ports:
  - "19530:19530"  # gRPC API
  - "9091:9091"    # 健康检查

两种连接方式

python 复制代码
from pymilvus import MilvusClient

# 方式一:连接远程服务(生产环境)
client = MilvusClient(uri="http://localhost:19530", token="root:Milvus")

# 方式二:连接本地文件数据库(Milvus Lite,适合开发调试)
client = MilvusClient(uri="./wukong.db")

数据库级隔离

Milvus 支持多数据库隔离,概念类似 MySQL 里的"数据库":

python 复制代码
# 创建数据库(可设置副本数)
client.create_database(db_name="my_database", properties={"database.replica.number": 3})

# 增删改查一套带走
client.list_databases()
client.describe_database(db_name="default")
client.use_database(db_name="my_database")
client.drop_database(db_name="my_database")

三、Collection / Partition / Alias 三剑客

这三个概念是 Milvus 数据组织的核心,面试必问!

1. Collection(集合)------ 类比"表"

集合是存储数据的基本单元。

python 复制代码
# 快速创建(自动生成 Schema)
client.create_collection(collection_name="quick_setup", dimension=5)

完整管理操作一览:

操作 方法 说明
列出集合 list_collections() 获取所有集合名
查看详情 describe_collection() 获取 Schema 和属性
重命名 rename_collection() 修改集合名称
设置属性 alter_collection_properties() 如设置 TTL
加载/释放 load_collection() / release_collection() 控制内存中的数据
删除 drop_collection() 永久删除集合

2. Partition(分区)------ 物理隔离加速查询

python 复制代码
client.create_partition(collection_name="my_col", partition_name="partA")
client.load_partitions(collection_name="my_col", partition_names=["partA"])
client.drop_partition(collection_name="my_col", partition_name="partA")

💡 典型场景:按时间(年/月)或地区分区,查询时只加载相关分区,大幅减少扫描量。

3. Alias(别名)------ 零停机切换神器

python 复制代码
client.create_alias(collection_name="my_col", alias="alias_v1")
client.alter_alias(collection_name="my_col_v2", alias="alias_v1")  # 切换指向
client.drop_alias(alias="alias_v1")

🚀 Alias 最经典场景 :重建索引时,新建 collection_v2 → 建好索引 → alter_alias 切换指向 → 用户完全无感知地完成了迁移。

实体 CRUD

python 复制代码
# 插入
client.insert(collection_name="my_col", data=[{"id": 1, "vector": [...], "color": "red"}])

# upsert:存在则更新,不存在则插入
client.upsert(collection_name="my_col", data=[{"id": 1, "vector": [...]}])

# 删除
client.delete(collection_name="my_col", ids=[0])

# 查询
client.query(collection_name="my_col", filter="id in [1,2]", output_fields=["id", "color"])

四、Schema 设计:字段类型全家桶

Schema 定义了集合的字段结构,Milvus 支持非常丰富的数据类型:

类别 数据类型 说明
主键 INT64 / VARCHAR 支持 auto_id 自动生成
向量 FLOAT_VECTOR 32位浮点密集向量
BINARY_VECTOR 二进制向量(维度须为8的倍数)
SPARSE_FLOAT_VECTOR 稀疏浮点向量(用于关键词检索)
标量 VARCHAR 字符串,需指定 max_length
INT32 / INT64 整数
BOOL 布尔值
JSON JSON 对象
ARRAY 数组,需指定 element_typemax_capacity

实战 Schema 示例

python 复制代码
from pymilvus import MilvusClient, DataType

schema = MilvusClient.create_schema(auto_id=False, enable_dynamic_field=True)

# 主键
schema.add_field(field_name="id", datatype=DataType.INT64, is_primary=True)

# 密集向量
schema.add_field(field_name="text_vector", datatype=DataType.FLOAT_VECTOR, dim=768)

# 稀疏向量(用于 BM25 全文检索)
schema.add_field(field_name="sparse", datatype=DataType.SPARSE_FLOAT_VECTOR)

# 标量字段
schema.add_field(field_name="title", datatype=DataType.VARCHAR, max_length=200,
                 is_nullable=True, default_value="untitled")
schema.add_field(field_name="metadata", datatype=DataType.JSON)
schema.add_field(field_name="tags", datatype=DataType.ARRAY,
                 element_type=DataType.VARCHAR, max_capacity=10, max_length=50)

🌟 Milvus 2.5+ 亮点:内置 BM25 函数

可以自动从文本生成稀疏向量,无需手动调 Embedding:

python 复制代码
from pymilvus import Function, FunctionType

schema.add_field(field_name="text", datatype=DataType.VARCHAR,
                 max_length=1000, enable_analyzer=True)
schema.add_field(field_name="sparse", datatype=DataType.SPARSE_FLOAT_VECTOR)

bm25_function = Function(
    name="text_bm25_emb",
    input_field_names=["text"],
    output_field_names=["sparse"],
    function_type=FunctionType.BM25,
)
schema.add_function(bm25_function)

五、🔑 核心:五大索引类型怎么选?

索引决定了向量搜索的性能和精度,这是向量数据库的灵魂。 先看一张全景对比图:

索引类型 全称 适用场景 关键参数 内存占用 搜索速度 精度
FLAT 暴力扫描 小数据集、要求100%精度 最高
IVF_FLAT 倒排文件 中等数据集 nlist, nprobe
IVF_PQ 倒排+乘积量化 大数据集、内存受限 nlist, m, nbits
HNSW 层次导航小世界 中大数据集、要求低延迟 M, efConstruction, ef 最快
DiskANN 磁盘近似最近邻 超大数据集 search_list 中高

各索引参数详解

1. FLAT ------ 暴力美学

适合小数据集,直接遍历所有向量,精度 100%。

2. IVF_FLAT ------ 先聚类再搜索

python 复制代码
index_params.add_index(field_name="vector", metric_type="L2", index_type="IVF_FLAT",
                       params={"nlist": 64})  # 聚类中心数量,通常 4*sqrt(n)
# 搜索参数
search_params={"params": {"nprobe": 10}}  # 搜索时检查的聚类数量

3. IVF_PQ ------ 乘积量化压缩(省内存利器)

python 复制代码
index_params.add_index(field_name="vector", metric_type="L2", index_type="IVF_PQ",
                       params={"nlist": 64, "m": 32, "nbits": 8})
# m:子向量数量,dim/m >= 2(如 128/32=4)
# nbits:每个子向量编码位数,通常为 8

📐 压缩效果有多猛? 128 维 × 4 字节 = 512 字节 → 8 × 1 字节 = 8 字节,压缩 64 倍!

4. HNSW ------ 当前最流行(推荐首选)

python 复制代码
index_params.add_index(field_name="vector", metric_type="L2", index_type="HNSW",
                       params={"M": 64, "efConstruction": 100})
# M:每个节点的最大邻居数(16~64),越大精度越高、内存越大
# efConstruction:构建时候选邻居数,越大构建越慢但质量越高
# 搜索参数
search_params={"params": {"ef": 10}}  # 搜索候选邻居数,越大越精确

🔥 为什么 HNSW 最火? 召回率通常 >99%,接近精确搜索;查询延迟亚毫秒级(图遍历只需几跳);无需训练,不像 IVF 需要 K-Means 聚类。

5. DiskANN ------ 十亿级数据的救星

python 复制代码
index_params.add_index(field_name="vector", metric_type="L2", index_type="DISKANN")
# 搜索参数
search_params={"params": {"search_list": 32}}  # 候选列表大小

内存中只存 PQ 压缩向量(每条几十字节),原始向量存 SSD。内存需求仅需数据量的 1/10 ~ 1/20,单机可处理十亿级!

度量方式怎么选?

度量类型 适用场景 距离含义
L2 连续数据、绝对距离 欧几里得距离(越小越相似)
IP(内积) 已归一化的向量 内积值(越大越相似)
COSINE 方向相似性、语义搜索 余弦相似度(越大越相似)

💡 选型口诀 :语义搜索首选 COSINE;向量已归一化用 IP(更快);需要精确距离用 L2

注:向量 L2 归一化后,COSINE 和 IP 等价,但用 IP 省去除法计算更快。


六、搜索全家桶:从 ANN 到迭代搜索

Milvus 的搜索能力非常丰富,一个 search() 方法能玩出花:

搜索类型 核心方法 用途
ANN 近似搜索 client.search() 基本向量相似搜索
过滤搜索 client.search(filter=...) 结合标量过滤条件
范围搜索 + radius/range_filter 查找距离在指定范围内的向量
分组搜索 + group_by_field 按字段分组去重
全文搜索 + BM25 关键词匹配
文本匹配 TEXT_MATCH() 精确文本匹配过滤
迭代搜索 client.search_iterator() 大规模分批获取结果
混合搜索 collection.hybrid_search() 多路检索融合

1. ANN 基本搜索

python 复制代码
# 单向量搜索
results = client.search(
    collection_name="my_col",
    data=[query_vector],      # 查询向量
    anns_field="vector",       # 向量字段名
    limit=3,                   # 返回 top-K
    search_params={"metric_type": "L2"},
    output_fields=["color"]    # 返回的标量字段
)

2. 过滤搜索:标准 vs 迭代

python 复制代码
# 标准过滤:先 ANN 搜索,再过滤
results = client.search(
    ...,
    filter='color like "color_%" and likes > 500',
    output_fields=["color", "likes"]
)

# 迭代过滤(hints="iterative_filter"):边搜索边过滤,精度更高
results = client.search(
    ...,
    search_params={"metric_type": "L2", "hints": "iterative_filter"},
    filter='color like "color_%" and likes > 500'
)

⚠️ 面试考点:当过滤条件会筛掉大量结果时,标准过滤可能返回不足,迭代过滤更可靠。

3. 范围搜索

python 复制代码
# L2 距离:range_filter < radius(距离 0.5~1.0 之间)
results = client.search(
    ...,
    search_params={
        "metric_type": "L2",
        "params": {"radius": 1.0, "range_filter": 0.5}
    }
)

⚠️ 方向别搞反 :L2 距离 range_filter < radius;IP/COSINE 则 range_filter > radius

4. 分组搜索 ------ RAG 必备!

python 复制代码
results = client.search(
    ...,
    group_by_field="docId",   # 按文档ID分组
    group_size=2,             # 每组返回2个结果
    strict_group_size=True    # 严格确保每组有足够结果
)

💡 为什么 RAG 场景必须有它? 同一文档被切成多个 chunk,不分组时同一文档的多个 chunk 可能霸占整个结果列表,导致返回内容单一。

5. 全文搜索(BM25)

python 复制代码
# 配置 BM25 索引
index_params.add_index(
    field_name="sparse",
    index_type="SPARSE_INVERTED_INDEX",
    metric_type="BM25",
    params={"inverted_index_algo": "DAAT_MAXSCORE", "bm25_k1": 1.2, "bm25_b": 0.75}
)

# 直接用文本搜索(无需手动编码向量!)
results = client.search(
    collection_name="my_col",
    data=["信息检索"],         # 直接传入文本
    anns_field='sparse',
    limit=3,
    search_params={'params': {'drop_ratio_search': 0.2}},
    output_fields=["text"]
)

6. 迭代搜索(SearchIterator)

适合需要获取大量结果的场景,分批返回:

python 复制代码
iterator = client.search_iterator(
    collection_name="my_col",
    data=[query_vector],
    anns_field="vector",
    search_params={"metric_type": "L2"},
    batch_size=1000,    # 每批1000条
    limit=20000,        # 总共最多20000条
    output_fields=["color"]
)

while True:
    result = iterator.next()
    if not result:
        iterator.close()
        break
    for hit in result:
        all_results.append(hit.to_dict())

七、LlamaIndex:更高层的抽象

直接用 Milvus 写代码比较繁琐,LlamaIndex 提供了更高层的封装:

概念 说明
Document 原始文档(来自文件、网页等)
Node 文档的一个片段(chunk),是索引和检索的基本单元
Index 数据结构,将 Node 组织为可检索的形式
VectorStoreIndex 最常用的索引类型,基于向量存储

四步构建索引

python 复制代码
from llama_index.core import SimpleDirectoryReader, VectorStoreIndex
from llama_index.core.node_parser import SentenceSplitter

# 1. 加载文档
documents = SimpleDirectoryReader("90-文档-Data").load_data()

# 2. 自定义切分(可选)
text_splitter = SentenceSplitter(chunk_size=512, chunk_overlap=10)
nodes = text_splitter.get_nodes_from_documents(documents)

# 3. 构建索引(从文档或从节点)
index = VectorStoreIndex.from_documents(documents)  # 自动切分
# 或
index = VectorStoreIndex(nodes)  # 使用自定义切分

# 4. 持久化到磁盘
index.storage_context.persist(persist_dir="saved_index")

LlamaIndex 帮你自动管理这些繁琐工作:节点切分、向量嵌入、文档关系、元数据保存,开发者只需关注业务逻辑。


八、🔥 重头戏:混合检索(Dense + Sparse)

混合检索是当前 RAG 系统的标配方案,结合了密集向量和稀疏向量的优势。

为什么必须混合?

用一个经典例子说明:

复制代码
查询: "苹果公司的市值"

Dense(语义匹配)✅                Sparse(关键词匹配)✅
┌─────────────────────┐         ┌─────────────────────┐
│ "Apple 的股价走势"    │  ←语义→  │                     │
│ "库克领导下的科技巨头" │  ←语义→  │                     │
│ "香蕉的价格"         │  ✗不匹配  │ "苹果公司发布新品"     │ ← 精确匹配"苹果公司"
└─────────────────────┘         │ "市值的计算方法"       │ ← 精确匹配"市值"
                                └─────────────────────┘
  • Dense 单独用:可能召回"苹果(水果)的价格"(语义混淆)
  • Sparse 单独用:可能漏掉"Apple 股价"(用词不同)
  • 融合后 :Dense 解决"词不同但意思相同",Sparse 解决"词相同但意思不同",完美互补!

核心模型:BGE-M3

BAAI/bge-m3 一次编码同时输出密集 + 稀疏向量:

python 复制代码
from milvus_model.hybrid import BGEM3EmbeddingFunction

ef = BGEM3EmbeddingFunction(use_fp16=False, device="cpu")
docs_embeddings = ef(docs)

# 密集向量:docs_embeddings["dense"]  → shape: (n, 1024)
# 稀疏向量:docs_embeddings["sparse"] → scipy 稀疏矩阵

架构示意

复制代码
查询文本 → BGE-M3 编码 → 密集向量 ──→ ANN 搜索 (dense_vector)  ──→ ┐
                          稀疏向量 ──→ 稀疏搜索 (sparse_vector) ──→ ├── 重排序 → 最终结果

双索引配置

python 复制代码
# 稀疏向量索引
collection.create_index("sparse_vector", {"index_type": "SPARSE_INVERTED_INDEX", "metric_type": "IP"})
# 密集向量索引
collection.create_index("dense_vector", {"index_type": "AUTOINDEX", "metric_type": "IP"})

两种重排序策略

1. WeightedRanker(加权重排)

python 复制代码
from pymilvus import AnnSearchRequest, WeightedRanker

dense_req = AnnSearchRequest(data=[dense_vec], anns_field="dense_vector", param=params, limit=5)
sparse_req = AnnSearchRequest(data=[sparse_vec], anns_field="sparse_vector", param=params, limit=5)

rerank = WeightedRanker(0.5, 1.0)  # 稀疏权重0.5,密集权重1.0
results = collection.hybrid_search(reqs=[dense_req, sparse_req], rerank=rerank, limit=5)

2. RRFRanker(基于排名的倒数融合)

python 复制代码
from pymilvus import RRFRanker

rerank = RRFRanker(k=60)  # k 为平滑参数
results = collection.hybrid_search(reqs=[dense_req, sparse_req], rerank=rerank, limit=5)

💡 选型建议 :需要精确控制权重用 WeightedRanker;不确定权重用 RRFRanker(更鲁棒)。


九、BGE-M3 与 ColBERT:延迟交互到底牛在哪?

BGE-M3 的 "M3" 指 Multi-lingual(多语言)、Multi-granularity(多粒度)、Multi-function(多功能) 。其中 Multi-function 是最大亮点:一个模型同时输出三种表示!

表示 维度/格式 捕获的信息 等价于
Dense(密集向量) 1024 维 float 语义相似性 类似 BGE-large 的嵌入
Sparse(稀疏向量) 词 → 权重的稀疏映射 关键词匹配 类似 BM25 / SPLADE
ColBERT(多向量) token × 1024 矩阵 细粒度 token 级交互 类似 ColBERT late interaction

三种交互方式对比

复制代码
┌─────────────────────────────────────────────────────────┐
│  Dense(单向量交互)                                       │
│  Query: [v_q]  ──── 余弦相似度 ────  Doc: [v_d]           │
│  1 个向量 vs 1 个向量  →  1 次计算                          │
│  ✅ 速度快  ❌ 丢失细粒度信息                                │
├─────────────────────────────────────────────────────────┤
│  Sparse(稀疏交互)                                        │
│  Query: {"苹果":0.8, "市值":0.6}                          │
│  Doc:   {"苹果":0.5, "公司":0.3}  → 词级别匹配             │
│  ✅ 精确匹配  ❌ 无法理解语义                                │
├─────────────────────────────────────────────────────────┤
│  ColBERT(延迟交互 / Late Interaction)                    │
│  Query tokens:  [q0] [q1] [q2] [q3]                      │
│                  ╳    ╳    ╳    ╳     ← 每对 token 都算   │
│  Doc tokens:    [d0] [d1] [d2] [d3] [d4] [d5]            │
│  N × M 次计算  →  精细的 token 级交互                       │
│  ✅ 最精细的匹配  ❌ 计算和存储开销大                         │
└─────────────────────────────────────────────────────────┘

ColBERT 打分公式

复制代码
Score(Q, D) = Σ_i  max_j  sim(q_i, d_j)

即:对 Query 中每个 token,找到 Document 中与它最相似的 token,
    把所有最佳匹配分数加起来作为最终得分。

🔑 一句话理解:Dense 是"早期交互"(先把文档压缩成一个向量,信息已丢失);ColBERT 是"延迟交互"(保留每个 token 的向量,打分时才交互),所以精度最高。

ColBERT 适合什么场景?

✅ 最适合:

  • 实体密集型检索:精确匹配人名、地名、产品名(如"iPhone 15 Pro Max 的价格")
  • 长文档段落检索:在 10 页合同中精确定位"违约赔偿条款"
  • 细微差异区分:"利率 3.5%" vs "利率 4.5%"
  • 跨语言 token 对齐:"Elon Musk" ↔ "埃隆·马斯克"

❌ 不适合:

  • 超大规模数据(>千万):每个文档存 N 个向量,开销太大
  • 实时性要求极高:延迟交互需 N×M 次计算
  • 短文本相似度:文本太短,token 级交互优势不明显

Milvus 能直接存 ColBERT 吗?

目前不能直接存 。原因:Milvus 的 FLOAT_VECTOR 字段要求固定维度,而 ColBERT 每个 doc 的 token 数不同(变长)。

最佳实践 ⭐:

复制代码
用 Dense + Sparse 做初筛召回(百万 → 百级)
再用 ColBERT / Cross-Encoder 做 Rerank 精排(百 → Top-10)

这样兼顾了规模和精度,是工业界最常用的方案。


十、多模态检索:图文跨模态怎么玩

基于 Visualized-BGE 模型,实现图像 + 文本的跨模态检索。

核心能力

在 BGE 基础上增加视觉编码器,支持两种模式:

python 复制代码
from visual_bge.modeling import Visualized_BGE

encoder = Visualized_BGE(model_name_bge="BAAI/bge-m3", model_weight="./Visualized_m3.pth")

# 纯图像编码
image_vector = encoder.encode(image="image.jpg")

# 图文联合编码(用于查询)
query_vector = encoder.encode(image="query.jpg", text="寻找战斗场景")

检索流程

复制代码
1. 数据准备:加载图像 + metadata.json
2. 编码入库:每张图像 → Visual-BGE 编码 → Milvus 存储
3. 查询检索:查询图像 + 查询文本 → 联合编码 → 向量搜索 → 返回相似图像
4. 可视化:查询图 + 检索结果 → 网格拼图展示

带过滤条件的搜索

python 复制代码
# 带余弦相似度范围的搜索
search_params = {
    "metric_type": "COSINE",
    "params": {"nprobe": 10, "radius": 0.1, "range_filter": 0.8}
}

# 带元数据过滤的搜索
filters = {"environment": "雪地", "category": "combat"}
# 等价于 filter 表达式: environment == '雪地' and category == 'combat'

中英文版本

版本 模型 语言
中文版 BAAI/bge-m3 + Visualized_m3.pth 中文查询
英文版 BAAI/bge-base-en-v1.5 + Visualized_base_en_v1.5.pth 英文查询

十一、🎯 速查表合集

索引选型决策树

复制代码
数据量级?
├── < 10万     → FLAT(精度优先)
├── 10万~100万 → HNSW(速度+精度平衡)
├── 100万~1000万 → IVF_FLAT / IVF_PQ(内存可控)
└── > 1000万   → DiskANN(磁盘存储)

搜索模式选择

复制代码
需求?
├── 语义相似     → 密集向量搜索(COSINE/IP)
├── 关键词匹配   → 稀疏向量搜索(BM25/Sparse)
├── 语义+关键词  → 混合搜索(hybrid_search)
├── 图像+文本    → 多模态检索(Visual-BGE)
├── 条件过滤     → 过滤搜索(filter 参数)
├── 按文档去重   → 分组搜索(group_by_field)
└── 大量结果     → 迭代搜索(search_iterator)

嵌入模型对照表

模型 类型 维度 特点
BAAI/bge-m3 多语言密集+稀疏 1024 混合检索首选
BAAI/bge-large-zh 中文密集 1024 中文语义搜索
BAAI/bge-base-en-v1.5 英文密集 768 英文语义搜索
Visualized-BGE 多模态 视模型而定 图文跨模态检索
text-embedding-3-large OpenAI API 3072 云端 API

Milvus 操作六步法

python 复制代码
from pymilvus import MilvusClient, DataType

client = MilvusClient(uri="http://localhost:19530")

# 创建 → 插入 → 索引 → 加载 → 搜索 → 释放
client.create_collection(collection_name="demo", dimension=768)
client.insert(collection_name="demo", data=data)
client.create_index(collection_name="demo", index_params=index_params)
client.load_collection(collection_name="demo")
results = client.search(collection_name="demo", data=[query_vec], limit=5)
client.release_collection(collection_name="demo")

十二、20 道高频面试题(建议背诵)

Q1:什么是向量数据库?和传统关系型数据库的区别?

核心区别在于查询方式 :关系型数据库做精确匹配(WHEREJOIN),向量数据库做相似度搜索(ANN)。向量数据库解决高维空间中的相似度检索问题,这是传统数据库无法高效完成的。

Q2:什么是 ANN?为什么不总用精确搜索?

  • KNN(精确):遍历所有向量,O(n)
  • ANN(近似):索引结构,亚线性时间

不用精确搜索的原因:数据量大时延迟不可接受;向量本身是近似表示,100% 精确意义不大;95%+ 召回率通常已够用。

Q3:L2、IP、COSINE 的区别?

  • L2:欧几里得距离,需绝对距离场景,受模长影响
  • IP:内积,向量已归一化时用,未归一化会失真
  • COSINE:余弦相似度,只看方向,语义搜索首选

向量 L2 归一化后 COSINE 和 IP 等价,用 IP 更快(省去除法)。

Q4:Milvus 五种索引的原理和适用场景?

索引 原理 适用规模 召回率 速度 内存
FLAT 暴力扫描 <10万 100% 最慢
IVF_FLAT K-Means 分桶,查 nprobe 个桶 百万级 ~95%
IVF_PQ 分桶 + 乘积量化压缩 亿级 ~90%
HNSW 多层导航图 千万级 >99% 最快
DiskANN 内存存 PQ 压缩向量,SSD 存原始 十亿级 ~95% 较快

Q5:HNSW 原理?为什么最流行?

分层可导航小世界图:上层稀疏(长距离边快速跨越),下层稠密(短距离边精确搜索)。从顶层入口贪心搜索,逐层下降到 Layer 0。

流行的原因:召回率 >99%、查询延迟亚毫秒级、无需训练。核心参数:M(16~64)、efConstructionef

Q6:IVF_PQ 乘积量化怎么压缩?

  1. D 维向量切分为 M 个子空间
  2. 每个子空间独立 K-Means(256 中心),形成码本
  3. 每段用 1 字节(0~255)代替 float32

压缩效果:128 维 512 字节 → 8 字节,压缩 64 倍

Q7:DiskANN 如何处理十亿级向量?

使用 Vamana 图算法构建全局导航图;内存只存 PQ 压缩向量(几十字节),原始向量存 SSD;查询时内存筛选候选 → SSD 读精确向量 → 重排;通过数据布局优化将随机读变为近似顺序读。

内存需求仅需数据量 1/10~1/20,单机处理十亿级

Q8:标准过滤和迭代过滤的区别?

  • 标准过滤:先 ANN 得 Top-K → 再 filter 过滤,可能返回不足
  • 迭代过滤 (hints="iterative_filter"):边搜索边过滤,扩大搜索范围,精度更高

过滤条件会筛掉大量结果时,迭代过滤更可靠。

Q9:什么是分组搜索?

group_by_field 分组,每组只返回最相似的 top-K。解决 RAG 中同一文档多个 chunk 占满结果的问题。

Q10:collection 的 load 和 release?

  • load:磁盘 → 内存(搜索前必须 load)
  • release:内存释放数据

Milvus 搜索在内存中执行,这是内存-磁盘分离架构的体现。

Q11:为什么 Dense + Sparse 要结合?

  • Dense 擅长语义理解,但可能语义混淆("苹果"水果 vs 公司)
  • Sparse 擅长精确匹配,但无法理解用词不同的同义表达

Dense 解决"词不同意思同",Sparse 解决"词同意不同",互补。

Q12:BGE-M3 能同时做语义和关键词搜索吗?

。一次编码同时输出三种表示:Dense(1024 维,语义)、Sparse(关键词)、ColBERT(token 级)。一个模型顶过去 BGE + BM25 两个。

Q13:WeightedRanker vs RRFRanker?

  • WeightedRanker:分数加权求和,知道哪路更可靠时用
  • RRFRanker :1/(k+rank) 排名倒数融合,不确定权重时用,更鲁棒

Q14:ColBERT 的延迟交互?

Dense 是早期交互(压缩时丢信息),ColBERT 保留每个 token 向量,打分时才交互:Score(Q,D) = Σ_i max_j sim(q_i, d_j)。精度最高,但存储计算开销大。

Q15:Milvus 能直接存 ColBERT 多向量吗?

不能FLOAT_VECTOR 要求固定维度,ColBERT 每个 doc token 数不同(变长)。替代方案:RAGatouille 等专用库,或 Dense+Sparse 初筛 + ColBERT 精排。

Q16:Visualized-BGE 如何跨模态检索?

在 BGE 基础上增加视觉编码器:纯图像编码 + 图文联合编码。入库时单图像编码,查询时图文联合编码后搜索相似向量。

Q17:法律文档检索系统怎么设计?

  1. 嵌入模型:BGE-M3
  2. 数据库:Milvus(HNSW + 混合搜索)
  3. 策略:Dense+Sparse 初筛 → ColBERT/Cross-Encoder 精排 → 分组去重
  4. Schema:双向量 + docId 分组 + 法律领域标量字段
  5. 过滤:案由、法院、时间范围

理由:法律对精确性要求极高,需要 ColBERT 的 token 级匹配。

Q18:10 万 → 10 亿索引如何演进?

阶段 数据量 索引 架构
初期 <10万 FLAT 单机 Lite
成长期 10万~100万 HNSW Standalone
扩展期 100万~1000万 IVF_FLAT/PQ 调优参数
大规模 1000万~1亿 IVF_PQ Cluster + 分区
超大规模 >1亿 DiskANN SSD + 内存压缩

Q19:Partition 和 Alias 解决什么问题?

  • Partition:集合内部物理隔离,加速查询(按时间/地区分区)
  • Alias:零停机切换集合(重建索引时新建 v2 → 切换别名)

Q20:RAG 召回率不够怎么优化?

按优先级:

  1. 换用混合检索(Dense + Sparse),通常 +10%
  2. 换索引(IVF_PQ → HNSW,~90% → >99%)
  3. 调参(增大 nprobe / ef)
  4. 加 Rerank(召回 Top-100,Cross-Encoder 精排 Top-10)
  5. 优化 Embedding 模型
  6. 优化分块策略
  7. 查询扩展(LLM 改写查询)

十三、总结

这篇文章把向量数据库的核心知识系统地梳理了一遍,关键要点回顾:

🎯 三步上手 Milvus:

  1. 理解 Collection / Partition / Alias 三层抽象
  2. 掌握 Schema 设计(密集向量 + 稀疏向量 + 标量字段)
  3. 索引选型牢记决策树:小数据 FLAT/HNSW,大数据 PQ/DiskANN

🔥 RAG 黄金组合:

复制代码
BGE-M3 编码 → Dense + Sparse 混合检索初筛 → ColBERT/Cross-Encoder Rerank 精排

💡 三个关键认知:

  1. ANN 牺牲少量精度换数量级速度,95% 召回率通常够用
  2. Dense + Sparse 互补,一个管语义一个管关键词
  3. ColBERT 精度最高但开销大,适合做 Rerank 而非初筛

📌 写在最后 :向量数据库是 AI 时代的基础设施,无论是 RAG、推荐系统还是多模态搜索都离不开它。这篇文章可以作为手册随时翻阅,建议收藏!

如果觉得有帮助,欢迎点赞 + 关注 + 收藏一键三连 ❤️,你的支持是我持续输出的动力!

有任何问题欢迎在评论区交流,我会一一回复~ 🙌


🏷️ 标签 :向量数据库 Milvus RAG 混合检索 BGE-M3 HNSW 语义搜索 人工智能

相关推荐
华奥系科技1 小时前
汛期城市内涝治理:智慧水务如何重塑防汛“安全感”?
大数据·运维·人工智能
aneasystone本尊1 小时前
给小龙虾配齐工具箱:OpenClaw 的工具体系
人工智能
m0_718677491 小时前
EaseChart:免费的流程图编辑器和付费的AI流程图Agent
人工智能
不羁的木木1 小时前
HarmonyOS AI开发提效工具:DevEco Code & DevEco CLI - 跨设备调试与AI应用部署
人工智能·华为·harmonyos·鸿蒙
我的世界洛天依1 小时前
胡桃讲编程:麻宫雅典娜 97 RVCv2 第一代(R1)开源发布文档 | 经典复古分支
人工智能
zhangfeng11331 小时前
JupyterLab 里,JSON文件纯文本格式编辑 / 查看
人工智能·json
Bode_20021 小时前
智能协同与绿色数字孪生舱主要功能与关键技术
大数据·人工智能·制造·碳中和
daly5201 小时前
人工智能专业有哪些?2026高考报考指南(专业分类 + 课程 + 就业全解析)
人工智能·分类·高考
暗夜猎手-大魔王1 小时前
转载--AgentScope 生产最佳实践
人工智能