1. 为什么需要向量数据库?
在传统的 SQL/NoSQL 数据库里,我们存储的是结构化或半结构化数据:订单、用户资料、JSON 文档……
但在大模型、推荐、搜索、RAG(Retrieval-Augmented Generation)等场景里,核心数据变成了高维向量(embedding)。
这些向量往往有 128、512、1536 甚至 4096 维,传统数据库无法高效地“按距离”检索,于是向量数据库应运而生。
一句话总结:
向量数据库 = 存储 + 索引 + 距离计算,专为“相似度搜索”优化。
2. 核心概念速览
| 概念 | 解释 | 举例 |
|---|---|---|
| Embedding | 把文本/图片/音频映射成固定维度的向量 | OpenAI text-embedding-3-small → 1536 维 |
| 距离度量 | 如何定义“相似” | L2(欧氏)、IP(内积)、Cosine |
| ANN | 近似最近邻搜索,牺牲少量精度换性能 | HNSW、IVF、DiskANN |
| 索引 | 把向量组织成可快速剪枝的结构 | HNSW 图、IVF 倒排 |
| 过滤搜索 | 先按标量过滤,再向量检索 | where city='Shanghai' and price<100 |
3. 主流产品全景图(2025)
| 产品 | 开源/商业 | 语言 | 特点 | 场景 |
|---|---|---|---|---|
| Milvus 2.x | Apache 2.0 | Go/C++ | 云原生、分布式、支持 GPU | 百亿级向量、多租户 |
| Weaviate | BSD | Go | GraphQL API、内置向量化模块 | 知识图谱、RAG |
| Qdrant | Apache 2.0 | Rust | 过滤+向量混合查询、Rust 性能 | 中小规模、边缘部署 |
| Pinecone | 商业 | SaaS | 全托管、自动扩缩容 | 初创公司、快速 PoC |
| pgvector | PostgreSQL 扩展 | C | 与 SQL 无缝融合 | 已有 PG 栈、低学习成本 |
| Chroma | Apache 2.0 | Python | 轻量级、嵌入式 | Notebook、原型验证 |
4. 技术内幕:HNSW 索引是如何工作的?
HNSW(Hierarchical Navigable Small World)是当前最热门的 ANN 算法之一,兼顾了召回率与延迟。
- 分层图:
最上层稀疏、最下层稠密,像“高速公路”+“城市道路”。 - 贪心搜索:
从上层入口节点开始,每层找局部最优邻居,逐层下降。 - 动态插入:
新向量插入时,只更新局部邻居,避免全局重建。
示意图(ASCII):
Layer 2: A ---------> C
Layer 1: A <-> B <-> C <-> D
Layer 0: A-B-C-D-E-F-G-H (全连接)
5. 实战:用 Milvus 构建“以图搜图”服务
5.1 环境准备
# 1. 启动 Milvus standalone(Docker Compose)
wget https://github.com/milvus-io/milvus/releases/download/v2.4.5/milvus-standalone-docker-compose.yml
docker compose -f milvus-standalone-docker-compose.yml up -d
# 2. 安装 Python SDK
pip install pymilvus==2.4.5 pillow torch torchvision
5.2 生成图片向量
# encode.py
import torch, torchvision.transforms as T
from torchvision.models import resnet50
from PIL import Image
import os, json, numpy as np
device = 'cuda' if torch.cuda.is_available() else 'cpu'
model = resnet50(weights='IMAGENET1K_V2')
model.fc = torch.nn.Identity() # 去掉分类头
model.eval().to(device)
transform = T.Compose([
T.Resize(256),
T.CenterCrop(224),
T.ToTensor(),
T.Normalize([0.485,0.456,0.406],
[0.229,0.224,0.225])
])
def encode_image(path):
img = Image.open(path).convert('RGB')
x = transform(img).unsqueeze(0).to(device)
with torch.no_grad():
vec = model(x).cpu().numpy().astype('float32')
return vec.flatten()
# 批量处理
vectors, ids = [], []
for idx, file in enumerate(os.listdir('images')):
vec = encode_image(f'images/{file}')
vectors.append(vec)
ids.append(idx)
np.save('vectors.npy', np.vstack(vectors))
json.dump(ids, open('ids.json','w'))
5.3 建表 & 插入
# milvus_demo.py
from pymilvus import (
connections, FieldSchema, CollectionSchema,
DataType, Collection, utility
)
connections.connect(alias="default", host="localhost", port="19530")
# 1. 定义 schema
dim = 2048 # ResNet50 输出维度
fields = [
FieldSchema(name="id", dtype=DataType.INT64, is_primary=True),
FieldSchema(name="vec", dtype=DataType.FLOAT_VECTOR, dim=dim)
]
schema = CollectionSchema(fields, "Image search demo")
collection = Collection("img_search", schema)
# 2. 创建 HNSW 索引
index_params = {
"index_type": "HNSW",
"metric_type": "L2",
"params": {"M": 16, "efConstruction": 200}
}
collection.create_index("vec", index_params)
collection.load()
# 3. 插入数据
import numpy as np, json
vectors = np.load('vectors.npy')
ids = json.load(open('ids.json'))
entities = [ids, vectors.tolist()]
collection.insert(entities)
collection.flush()
5.4 查询
# search.py
from pymilvus import connections, Collection
import encode # 复用上面的 encode_image
connections.connect("default", host="localhost", port="19530")
collection = Collection("img_search")
collection.load()
query_vec = encode.encode_image('query/cat.jpg').tolist()
search_params = {"metric_type": "L2", "params": {"ef": 64}}
results = collection.search(
data=[query_vec],
anns_field="vec",
param=search_params,
limit=5,
output_fields=["id"]
)
for hits in results:
for hit in hits:
print("id:", hit.id, "distance:", hit.distance)
6. 性能调优清单
| 维度 | 建议 |
|---|---|
| 索引类型 | 百万级用 HNSW;十亿级用 IVF_PQ 或 DiskANN |
| 维度 | 高维(>1024) 建议量化(INT8/INT4) |
| 内存 | HNSW 内存 ≈ 1.1 × 向量数 × 维度 × 4B |
| 并发 | 调整 ef 参数:查询延迟 vs 召回率 |
| 过滤 | 先标量过滤再向量搜索,减少候选集 |
7. 常见坑 & 解决方案
- 维度不一致
报错:dimension not match
→ 插入前统一做assert vec.shape[0] == dim。 - 召回率下降
可能ef太小,或量化损失过大。
→ 线上 A/B 测试,逐步调大ef或降低量化比例。 - 内存爆炸
单机 HNSW 无法承载十亿向量。
→ 使用 Milvus 分布式模式,或 DiskANN 磁盘索引。
8. 未来展望
- 多模态融合:一张图 + 一段文本 → 联合向量
- 实时增量:Kafka → Embedding 模型 → 向量 DB → 毫秒级更新
- Serverless:按查询计费,无需关心分片、副本
- 硬件加速:GPU 索引(NVIDIA RAFT)、CXL 内存池
9. 一句话总结
向量数据库不是“又一个 NoSQL”,而是 AI 应用的核心基础设施。
从推荐、搜索到 AIGC,谁能把 Embedding 存得快、搜得准,谁就拥有了下一代数据平台的门票。
Happy embedding!
Comments NOTHING