引言
在RAG系统中,向量数据库是核心组件之一。选择合适的向量数据库直接影响系统的性能、成本和可维护性。
本文将对比2024年主流的向量数据库:Pinecone、Chroma、Milvus、Weaviate 和 pgvector,帮助你做出正确选择。
快速对比
| 特性 | Pinecone | Chroma | Milvus | Weaviate | pgvector |
|---|---|---|---|---|---|
| 部署方式 | 托管SaaS | 本地/容器 | 本地/K8s/云 | 本地/云 | PostgreSQL扩展 |
| 开源 | ❌ | ✅ | ✅ | ✅ | ✅ |
| 最大维度 | 20,000 | 无限制 | 32,768 | 65,536 | 16,000 |
| 元数据过滤 | ✅ | ✅ | ✅ | ✅ | ✅ |
| 混合检索 | ✅ | ❌ | ✅ | ✅ | ✅ |
| 多租户 | ✅ | ❌ | ✅ | ✅ | ✅ |
| 水平扩展 | ✅ | ❌ | ✅ | ✅ | ✅ |
Pinecone
特点
托管向量数据库,无需运维,专注于业务开发。
import pinecone
# 初始化
pinecone.init(api_key="your-api-key", environment="us-west1-gcp")
# 创建索引
index = pinecone.create_index(
name="my-index",
dimension=1536,
metric="cosine",
pod_type="p1.x1"
)
# 插入数据
index.upsert([
("id-1", [0.1, 0.2, ...], {"category": "tech"}),
("id-2", [0.3, 0.4, ...], {"category": "science"}),
])
# 查询
results = index.query(
vector=[0.1, 0.2, ...],
top_k=10,
filter={"category": {"$eq": "tech"}}
)
优点
- ✅ 零运维 - 全托管服务
- ✅ 高性能 - 企业级性能保障
- ✅ 快速启动 - 几分钟内上线
- ✅ 自动扩展 - 根据负载自动调整
- ✅ 混合检索 - 支持稀疏向量
缺点
- ❌ 闭源 - 无法自主控制
- ❌ 成本 - 大规模数据成本较高
- ❌ Vendor Lock-in - 迁移成本
适用场景
- 快速原型开发
- 不想运维基础设施
- 预算充足的企业
定价
| 套餐 | 价格 | 特点 |
|---|---|---|
| Starter | 免费 | 1个索引,10万向量 |
| Standard | $70/月 | 多索引,支持元数据过滤 |
| Enterprise | 定制 | 专用资源,SLA保障 |
Chroma
特点
开源向量数据库,简单易用,适合本地开发和小型项目。
import chromadb
# 客户端模式
client = chromadb.Client()
# 持久化模式
client = chromadb.PersistentClient(path="./chroma_db")
# 创建集合
collection = client.create_collection(
name="documents",
metadata={"hnsw:space": "cosine"}
)
# 添加文档
collection.add(
documents=["文档1内容", "文档2内容"],
metadatas=[{"category": "tech"}, {"category": "science"}],
ids=["doc-1", "doc-2"]
)
# 查询
results = collection.query(
query_texts=["查询内容"],
n_results=10,
where={"category": "tech"}
)
优点
- ✅ 开源免费 - Apache 2.0协议
- ✅ 简单易用 - API直观简洁
- ✅ 轻量级 - 资源占用少
- ✅ 自动嵌入 - 内置嵌入模型支持
- ✅ 多语言 - Python/JS/Rust
缺点
- ❌ 无分布式 - 不支持水平扩展
- ❌ 功能简单 - 缺少高级功能
- ❌ 生产限制 - 不适合大规模生产
适用场景
- 本地开发和测试
- 小型项目
- 学习和原型
Milvus
特点
企业级开源向量数据库,支持大规模分布式部署。
from pymilvus import connections, FieldSchema, CollectionSchema, DataType, Collection
# 连接
connections.connect(host="localhost", port="19530")
# 定义字段
fields = [
FieldSchema(name="id", dtype=DataType.INT64, is_primary=True),
FieldSchema(name="embedding", dtype=DataType.FLOAT_VECTOR, dim=1536),
FieldSchema(name="text", dtype=DataType.VARCHAR, max_length=65535),
]
# 创建集合
schema = CollectionSchema(fields, "文档集合")
collection = Collection("documents", schema)
# 创建索引
index_params = {
"index_type": "IVF_FLAT",
"metric_type": "COSINE",
"params": {"nlist": 128}
}
collection.create_index(field_name="embedding", index_params=index_params)
# 插入数据
collection.insert([[1, 2, 3], [[0.1, 0.2, ...], [0.3, 0.4, ...]], ["text1", "text2"]])
# 搜索
collection.load()
results = collection.search(
data=[[0.1, 0.2, ...]],
anns_field="embedding",
param={"metric_type": "COSINE", "params": {"nprobe": 10}},
limit=10
)
优点
- ✅ 开源企业级 - Apache 2.0,功能丰富
- ✅ 分布式 - 支持水平扩展
- ✅ 多种索引 - IVF、HNSW、DiskANN等
- ✅ 混合检索 - 向量+标量联合查询
- ✅ 云原生 - Kubernetes原生支持
缺点
- ❌ 运维复杂 - 组件多,部署复杂
- ❌ 学习曲线 - 概念较多,上手较难
适用场景
- 大规模生产环境
- 需要水平扩展
- 企业级应用
Weaviate
特点
开源向量搜索引擎,强调语义搜索和GraphQL接口。
import weaviate
# 连接
client = weaviate.Client("http://localhost:8080")
# 创建类
class_obj = {
"class": "Document",
"vectorizer": "text2vec-openai",
"moduleConfig": {
"text2vec-openai": {
"vectorizeClassName": False
}
},
"properties": [
{"name": "title", "dataType": ["text"]},
{"name": "content", "dataType": ["text"]},
]
}
client.schema.create_class(class_obj)
# 插入数据
client.data_object.create(
{"title": "文档标题", "content": "文档内容"},
"Document"
)
# GraphQL查询
query = '''
{
Get {
Document(
nearText: {
concepts: ["查询内容"]
}
limit: 10
) {
title
content
_additional { certainty }
}
}
}
'''
results = client.query.raw(query)
优点
- ✅ GraphQL - 现代化的查询接口
- ✅ 模块化 - 可插拔的向量化模块
- ✅ 多模态 - 支持文本、图像等
- ✅ 向量模块化 - 内置多种嵌入模型
缺点
- ❌ 资源占用 - 内存需求较高
- ❌ 生态较小 - 社区相对较小
适用场景
- 需要GraphQL接口
- 多模态搜索
- 语义搜索应用
pgvector
特点
PostgreSQL向量扩展,在熟悉的SQL数据库中使用向量功能。
-- 启用扩展
CREATE EXTENSION vector;
-- 创建表
CREATE TABLE documents (
id SERIAL PRIMARY KEY,
content TEXT,
embedding vector(1536)
);
-- 创建索引
CREATE INDEX ON documents USING ivfflat (embedding vector_cosine_ops)
WITH (lists = 100);
-- 插入数据
INSERT INTO documents (content, embedding)
VALUES ('文档内容', '[0.1, 0.2, ...]');
-- 相似度查询
SELECT id, content,
1 - (embedding <=> '[0.1, 0.2, ...]') AS similarity
FROM documents
ORDER BY embedding <=> '[0.1, 0.2, ...]'
LIMIT 10;
from sqlalchemy import create_engine, text
# 连接
engine = create_engine("postgresql://user:pass@localhost/db")
# 查询
with engine.connect() as conn:
result = conn.execute(text("""
SELECT id, content, 1 - (embedding <=> :embedding) AS similarity
FROM documents
ORDER BY embedding <=> :embedding
LIMIT 10
"""), {"embedding": str([0.1, 0.2, ...])})
for row in result:
print(row)
优点
- ✅ SQL熟悉 - 使用标准SQL
- ✅ ACID - 完整的事务支持
- ✅ Join操作 - 向量+关系数据联合查询
- ✅ 生态丰富 - PostgreSQL生态
- ✅ 运维简单 - 统一运维
缺点
- ❌ 性能限制 - 不如专用向量数据库
- ❌ 功能有限 - 缺少高级向量功能
- ❌ 扩展性 - 受限于PostgreSQL
适用场景
- 已有PostgreSQL基础设施
- 需要关系+向量联合查询
- 数据量不大(小于100万)
选型决策树
开始
│
├─ 是否需要快速上线?
│ ├─ 是 → Pinecone(托管服务)
│ └─ 否 → 继续
│
├─ 数据量是否 > 1000万?
│ ├─ 是 → Milvus(分布式)
│ └─ 否 → 继续
│
├─ 是否已有PostgreSQL?
│ ├─ 是 → pgvector(简单扩展)
│ └─ 否 → 继续
│
├─ 是否需要GraphQL?
│ ├─ 是 → Weaviate
│ └─ 否 → 继续
│
└─ 本地开发/小型项目?
├─ 是 → Chroma
└─ 否 → Milvus(功能最全面)
性能对比
| 数据库 | 10万向量 | 100万向量 | 1000万向量 |
|---|---|---|---|
| Pinecone | 10ms | 15ms | 20ms |
| Chroma | 20ms | 100ms | N/A |
| Milvus | 15ms | 20ms | 30ms |
| Weaviate | 25ms | 40ms | 60ms |
| pgvector | 30ms | 200ms | 1000ms+ |
注:实际性能取决于硬件配置和索引参数
成本对比
| 数据库 | 小规模 | 中规模 | 大规模 |
|---|---|---|---|
| Pinecone | $0-70/月 | $200-500/月 | $1000+/月 |
| Chroma | 免费 | 免费 | 需自建 |
| Milvus | 免费 | 免费 | 云托管$500+/月 |
| Weaviate | 免费 | 免费 | 云托管$300+/月 |
| pgvector | 免费 | 免费 | 免费 |
总结建议
| 场景 | 推荐 | 理由 |
|---|---|---|
| 快速原型 | Chroma | 零配置,快速启动 |
| 生产环境 | Pinecone | 托管服务,稳定可靠 |
| 大规模数据 | Milvus | 分布式,水平扩展 |
| 已有PG | pgvector | 无缝集成,统一运维 |
| 语义搜索 | Weaviate | GraphQL,模块化设计 |
迁移策略
如果后期需要迁移:
# 通用迁移脚本框架
import json
def migrate(source_db, target_db):
"""通用向量数据库迁移"""
# 1. 导出数据
vectors = source_db.export_all()
# 2. 转换格式
converted = [
{
"id": v.id,
"vector": v.vector,
"metadata": v.metadata
}
for v in vectors
]
# 3. 批量导入
target_db.batch_insert(converted)
# 4. 验证
assert target_db.count() == source_db.count()
本文最后更新于 2024-01-22,如有问题欢迎在社区讨论。