向量数据库选型与生产级实战

04 · 向量数据库选型与生产级实战

Embedding 做好了,向量往哪存?本篇深入 pgvector、Chroma、Milvus 三大方案,用 Node.js 做生产级对比和实战。


1. 向量数据库的核心问题

选向量数据库不是在选"最快的那个",而是在回答三个问题:

  1. 我的数据量会涨到多大? ------决定了需要单机还是分布式
  2. 我的 QPS 要求多高? ------决定了索引类型和硬件配置
  3. 我的团队能运维什么? ------决定了用托管服务还是自建

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 优化

相关推荐
灏仟亿前端技术团队1 小时前
B 端多弹窗越来越难维护?试试把弹窗交互 Promise 化
前端
徐小夕2 小时前
jitword 协同文档3.2发布:打造浏览器中最强word编辑器
前端·架构·github
纯爱掌门人4 小时前
干了这么多年前端,聊聊 2026 年我们到底还值不值钱
前端·程序员
houhou4 小时前
Monaco Editor 集成指南:从配置到优化
前端
hunterandroid4 小时前
[Android 从零到一] Custom View 自定义绘制:从 onDraw 到完整交互
前端
李明卫杭州4 小时前
Vue3 v-memo 指令详解:让你的列表渲染性能翻倍 🚀
前端
梨子同志4 小时前
Monorepo
前端
lihaozecq4 小时前
继 Web Coding Agent 后,我做了一个本地优先的桌面 AI Agent
前端·agent
用户298698530144 小时前
在 React 中使用 JavaScript 将 Excel 转换为 SVG
前端·javascript·react.js