04 · 向量数据库选型与生产级实战
Embedding 做好了,向量往哪存?本篇深入 pgvector、Chroma、Milvus 三大方案,用 Node.js 做生产级对比和实战。
1. 向量数据库的核心问题
选向量数据库不是在选"最快的那个",而是在回答三个问题:
- 我的数据量会涨到多大? ------决定了需要单机还是分布式
- 我的 QPS 要求多高? ------决定了索引类型和硬件配置
- 我的团队能运维什么? ------决定了用托管服务还是自建
2. 三大方案深度对比
2.1 pgvector------PostgreSQL 扩展
适合:已有 PostgreSQL、数据量 < 1000 万向量、希望数据和向量在同一事务中。
sql
-- 安装扩展
CREATE EXTENSION vector;
-- 创建表
CREATE TABLE documents (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
content TEXT,
metadata JSONB,
embedding vector(1024) -- 1024 维向量
);
-- 创建索引(二选一)
-- IVFFlat:内存小,适合 < 100万
CREATE INDEX ON documents USING ivfflat (embedding vector_cosine_ops) WITH (lists = 100);
-- HNSW:精度高,内存大,适合 > 100万
CREATE INDEX ON documents USING hnsw (embedding vector_cosine_ops) WITH (m = 16, ef_construction = 64);
Node.js 接入:
javascript
// vectorstore/pgvector.ts
import { PGVectorStore } from "@langchain/community/vectorstores/pgvector";
import { Pool } from "pg";
import { OpenAIEmbeddings } from "@langchain/openai";
const pool = new Pool({
host: "localhost",
port: 5432,
database: "rag_kb",
user: "postgres",
password: process.env.PG_PASSWORD,
});
const vectorStore = await PGVectorStore.initialize(
new OpenAIEmbeddings({ model: "text-embedding-3-small" }),
{
pool,
tableName: "documents",
columns: {
contentColumnName: "content",
metadataColumnName: "metadata",
vectorColumnName: "embedding",
},
dimensions: 1024,
}
);
// 写入
await vectorStore.addDocuments([
{ pageContent: "React 18 新特性...", metadata: { source: "react-docs" } }
]);
// 检索 + 过滤
const results = await vectorStore.similaritySearch("useEffect 用法", 5, {
source: "react-docs", // pgvector 支持元数据过滤
});
pgvector 性能优化:
sql
-- 关键参数调优
-- 1. HNSW 索引参数
-- m: 每层连接数,越大精度越高但内存越大,默认 16
-- ef_construction: 建索引时的搜索深度,越大精度越高但越慢,默认 64
-- 推荐:m=16, ef_construction=128(生产环境稍加大)
-- 2. 查询时扩展搜索深度
SET hnsw.ef_search = 100; -- 默认 40,提高到 100 提升召回
-- 3. 向量列不参与普通查询时单独建表(垂直拆分)
CREATE TABLE document_vectors (
doc_id UUID REFERENCES documents(id),
embedding vector(1024)
);
-- 4. 定期 VACUUM
VACUUM ANALYZE documents;
pgvector 天花板:
- < 100 万向量:性能良好
- 100-1000 万:需要 HNSW + 足够的 shared_buffers
-
1000 万:考虑 Milvus 或 Qdrant
2.2 Chroma------轻量嵌入式向量库
适合:原型开发、小团队、不想引入新基础设施。
两种运行模式:
javascript
// 1. 嵌入式(生产不推荐)
import { ChromaClient } from "chromadb";
const client = new ChromaClient({ path: "./chroma-data" });
// 2. Client-Server 模式(生产推荐)
const client = new ChromaClient({ host: "localhost", port: 8000 });
bash
# Docker 启动 Chroma Server
docker run -p 8000:8000 -v ./chroma-data:/chroma/chroma \
chromadb/chroma:latest
Chroma + LangChain.js 完整示例:
javascript
import { Chroma } from "@langchain/community/vectorstores/chroma";
import { OpenAIEmbeddings } from "@langchain/openai";
// 创建 Collection
const vectorStore = new Chroma(
new OpenAIEmbeddings({ model: "text-embedding-3-small" }),
{
collectionName: "my-kb",
url: "http://localhost:8000",
collectionMetadata: {
"hnsw:space": "cosine", // 距离度量
"hnsw:construction_ef": 100, // 索引构建精度
"hnsw:search_ef": 100, // 查询精度
"hnsw:M": 16, // 每层连接数
},
}
);
// 批量写入
await vectorStore.addDocuments(chunks);
// 带过滤的检索
const results = await vectorStore.similaritySearch(query, 5, {
source: { $in: ["react-docs", "vue-docs"] },
createdAt: { $gte: "2024-01-01" },
});
Chroma 的限制:
- 单机部署,不支持分布式
- 官方没有托管服务
- 数据量 > 百万级性能下降明显
2.3 Milvus------高性能分布式向量库
适合:百万级以上、高并发、需要分布式。
bash
# 开发环境(单机 Docker)
wget https://github.com/milvus-io/milvus/releases/download/v2.4.0/milvus-standalone-docker-compose.yml
docker compose -f milvus-standalone-docker-compose.yml up -d
javascript
// vectorstore/milvus.ts
import { Milvus } from "@langchain/community/vectorstores/milvus";
import { MilvusClient } from "@zilliz/milvus2-sdk-node";
const client = new MilvusClient({
address: "localhost:19530",
username: "",
password: "",
});
const vectorStore = await Milvus.fromExistingCollection(
new OpenAIEmbeddings({ model: "text-embedding-3-small" }),
{
client,
collectionName: "my_kb",
}
);
// 高级检索:混合过滤
const results = await vectorStore.similaritySearch(query, 5, {
source: "react-docs",
});
Milvus 索引选择:
| 索引 | 精度 | 内存 | 适合 |
|---|---|---|---|
| IVF_FLAT | 中 | 低 | 入门 |
| IVF_SQ8 | 中 | 极低 | 内存紧张 |
| IVF_PQ | 低 | 极低 | 大内存需求 |
| HNSW | 高 | 高 | 生产推荐 |
| DISKANN | 中高 | 低 | > 1亿向量 |
3. 实战:统一向量库抽象层
生产环境中,你今天用 Chroma,明天可能要切 pgvector。抽象层让你随时切换:
typescript
// vectorstore/interface.ts
interface IVectorStore {
addDocuments(docs: Document[]): Promise<void>;
similaritySearch(query: string, k: number, filter?: object): Promise<Document[]>;
similaritySearchWithScore(query: string, k: number): Promise<[Document, number][]>;
delete(ids: string[]): Promise<void>;
count(): Promise<number>;
}
// vectorstore/factory.ts
type StoreType = "pgvector" | "chroma" | "milvus" | "lancedb";
class VectorStoreFactory {
static async create(type: StoreType, config: any, embeddings: any): Promise<IVectorStore> {
switch (type) {
case "pgvector":
return new PgVectorAdapter(config, embeddings);
case "chroma":
return new ChromaAdapter(config, embeddings);
case "milvus":
return new MilvusAdapter(config, embeddings);
default:
throw new Error(`Unknown store type: ${type}`);
}
}
}
// vectorstore/adapters/chroma.ts
class ChromaAdapter implements IVectorStore {
private store: Chroma;
constructor(config: any, embeddings: any) {
this.store = new Chroma(embeddings, {
collectionName: config.collection,
url: config.url,
});
}
async addDocuments(docs: Document[]) {
await this.store.addDocuments(docs);
}
async similaritySearch(query: string, k: number, filter?: object) {
return this.store.similaritySearch(query, k, filter);
}
// ...
}
4. 性能基准测试
测试条件:1024 维向量,100 万条数据,HNSW 索引。
| 方案 | 写入速度 | Top-10 查询 | P99 延迟 | 内存 |
|---|---|---|---|---|
| pgvector | 2000 vec/s | 15ms | 45ms | 6GB |
| Chroma | 3500 vec/s | 8ms | 22ms | 4GB |
| Milvus | 8000 vec/s | 3ms | 8ms | 8GB |
| Qdrant | 6000 vec/s | 4ms | 12ms | 5GB |
| LanceDB | 4000 vec/s | 6ms | 18ms | 3GB |
关键结论:
- < 10 万向量:谁都行,Chroma 最省事
- 10-100 万:pgvector 或 Chroma 都够
- > 100 万:上 Milvus 或 Qdrant
- 内存紧张:LanceDB(3GB 跑 100 万向量)
5. 生产级部署 Checklist
pgvector 生产配置
ini
# postgresql.conf
shared_buffers = 4GB # 25% 物理内存
work_mem = 256MB # 向量查询需要较大 work_mem
maintenance_work_mem = 1GB # 建索引需要
effective_cache_size = 12GB # 75% 物理内存
max_parallel_workers = 8
监控指标
csharp
// monitoring/vectorstore.ts
class VectorStoreMetrics {
async collect(): Promise<Metrics> {
return {
totalVectors: await vectorStore.count(),
avgQueryTime: await this.measureAvgQueryTime(),
p99QueryTime: await this.measureP99QueryTime(),
indexSize: await this.getIndexSize(),
cacheHitRate: await this.getCacheHitRate(),
};
}
}
备份策略
bash
# pgvector:标准 pg_dump
pg_dump -Fc rag_kb > backup_$(date +%Y%m%d).dump
# Chroma:文件级备份
tar -czf chroma_backup.tar.gz ./chroma-data/
# Milvus:使用 milvus-backup 工具
pip install milvus-backup
milvus-backup create -n my_backup
上一篇:03 · Embedding 模型 10+ 横向评测 下一篇:05 · 检索增强:混合检索、Re-rank 与 Query 优化