共计 2625 个字符,预计需要花费 7 分钟才能阅读完成。
背景痛点:为什么我们需要向量数据库?
在推荐系统和图像识别等场景中,我们经常需要处理海量的非结构化数据,比如图片、视频、文本等。这些数据通常被表示为高维向量(比如 512 维或 1024 维),传统的数据库无法高效处理这种数据的检索需求。

- 传统数据库的局限性 :关系型数据库无法有效支持向量相似度计算,全表扫描的复杂度是 O(N),当数据量达到百万级时查询变得极其缓慢
- 刚性需求场景 :
- 电商推荐:” 找相似商品 ” 功能需要实时计算商品向量间的余弦相似度
- 人脸识别:需要从千万级人脸库中快速找到最匹配的几张人脸
- 语义搜索:文本嵌入向量的近邻检索
16 个主流向量数据库横向对比
我们从索引类型、架构设计、存储开销三个维度对比主流方案:
1. 索引类型差异
- Faiss:主打 IVF(倒排文件)+PQ(乘积量化) 组合,适合高精度场景
- Milvus:支持多种索引 (IVF_FLAT、HNSW、ANNOY),可运行时切换
- Weaviate:默认使用 HNSW 图算法,平衡查询速度与召回率
- Pinecone:全托管服务,底层使用改良版 HNSW
2. 架构设计对比
| 数据库 | 单机版 | 分布式 | 云原生 |
|---|---|---|---|
| Faiss | ✓ | ✗ | ✗ |
| Milvus | ✓ | ✓ | ✓ |
| Qdrant | ✓ | ✓ | ✓ |
| Pinecone | ✗ | ✓ | ✓ |
3. 存储开销示例 (以 100 万 768 维向量为例)
- Faiss(IVF2048,PQ16):约 1.2GB 内存
- Milvus(HNSW):约 3.5GB 内存
- Weaviate:需要额外 20% 空间存储图结构
核心实现:从代码到部署
Faiss 实战:IVFFlat 索引构建
import faiss
import numpy as np
# 数据准备
d = 768 # 向量维度
nb = 1000000 # 数据库大小
nq = 10 # 查询数量
np.random.seed(1234)
xb = np.random.random((nb, d)).astype('float32')
xb[:, 0] += np.arange(nb) / 1000. # 添加少量噪声
xq = np.random.random((nq, d)).astype('float32')
# 数据归一化
faiss.normalize_L2(xb)
faiss.normalize_L2(xq)
# 构建索引
nlist = 1024 # 聚类中心数
quantizer = faiss.IndexFlatL2(d)
index = faiss.IndexIVFFlat(quantizer, d, nlist)
assert not index.is_trained
index.train(xb) # 训练聚类器
assert index.is_trained
index.add(xb) # 添加向量
# GPU 加速
res = faiss.StandardGpuResources()
gpu_index = faiss.index_cpu_to_gpu(res, 0, index)
# 查询
k = 5 # topK
D, I = gpu_index.search(xq, k) # D 是距离,I 是索引
Milvus 快速部署
# Docker 单机版
docker pull milvusdb/milvus:2.3.0
docker run -d --name milvus \
-p 19530:19530 \
-p 9091:9091 \
milvusdb/milvus:2.3.0
from pymilvus import connections, CollectionSchema, FieldSchema, DataType, Collection
# 连接
connections.connect("default", host="localhost", port="19530")
# 定义 schema
fields = [FieldSchema("id", DataType.INT64, is_primary=True),
FieldSchema("embedding", DataType.FLOAT_VECTOR, dim=768)
]
schema = CollectionSchema(fields)
# 创建 collection
collection = Collection("my_collection", schema)
# 插入数据
import numpy as np
data = [[i for i in range(100)], # ids
np.random.random((100, 768)).tolist() # vectors]
collection.insert(data)
性能考量与优化
查询延迟测试 (top_k 影响)
import time
def test_query(collection, top_k):
start = time.time()
collection.search(
data=query_vectors,
anns_field="embedding",
param={"metric_type": "L2", "params": {"nprobe": 10}},
limit=top_k
)
return time.time() - start
# 测试结果 (100 维向量,100 万数据量)
# top_k=5 → 12ms
# top_k=50 → 45ms
# top_k=500 → 320ms
批量插入优化
- 线程安全方案 :
- 使用消息队列缓冲写入请求
- 批量聚合达到阈值后统一写入
- 采用乐观锁控制并发
避坑指南
1. 维度对齐错误
典型报错 :
ValueError: Expected 768 dimensions, got 512
解决方法 :
1. 插入前检查向量维度
assert len(vector) == collection.schema["embedding"].dim
2. 使用预处理层统一维度
from sentence_transformers import SentenceTransformer
model = SentenceTransformer('all-mpnet-base-v2') # 固定输出 768 维
2. 集群配置要点
- 一致性哈希 :
- 每个节点负责一段哈希环
- 数据迁移时采用虚拟节点减少热点
- 配置示例 (Qdrant):
cluster: enabled: true p2p: port: 6335 consensus: tick_period_ms: 100
思考题
在实际业务中,我们经常需要同时考虑向量相似度和关键词匹配度。 如何设计混合检索(向量 + 关键词)的排序策略? 可以从以下角度思考:
1. 线性加权:相似度_score = α×向量分 + (1-α)×关键词分
2. 分层筛选:先用关键词过滤,再对结果集做向量搜索
3. 学习排序 (LTR):训练模型预测综合相关性
正文完
发表至: 未分类
近两天内
