Files
2026-07-13 21:36:42 +08:00

14 KiB
Raw Permalink Blame History

向量数据库


数据库对比矩阵

特性 Pinecone Weaviate Qdrant Chroma pgvector
托管方式 仅托管 托管 + 自托管 托管 + 自托管 自托管(云版内测中) 自托管
混合搜索 支持(稀疏-稠密) 支持(BM25 + 向量) 支持(稀疏向量) 有限 手动(+ pg_trgm
过滤能力 优秀 优秀 优秀 基础 SQL 原生
最大维度 20,000 无限 65,535 无限 2,000
定价模式 按向量/查询计费 按节点计费 按节点计费 免费(开源) 免费(扩展)
多租户 命名空间 多租户类 集合 + 负载 集合 Schema/RLS
最适合 企业级 SaaS 语义应用 高性能场景 原型开发 PostgreSQL 用户

何时使用各方案

Pinecone

最适合:
- 有严格 SLA 的企业级 RAG
- 希望零基础设施管理的团队
- 需要稀疏-稠密混合搜索的应用
- 成本可预测的高并发生产环境

应避免:
- 成本敏感型项目(大规模时价格昂贵)
- 需要自托管或数据本地化
- 超出元数据的复杂过滤需求
- 希望避免厂商锁定

Weaviate

最适合:
- 带内置向量化的语义搜索
- 多模态(文本、图像)应用
- GraphQL 原生团队
- 需要 BM25 + 向量混合搜索

应避免:
- 仅需简单嵌入存储
- 内存受限的环境
- 不熟悉 GraphQL 的团队

Qdrant

最适合:
- 高性能、低延迟需求
- 带负载索引的复杂过滤
- Rust/性能优先团队
- 自托管,完全控制

应避免:
- 希望完全托管便捷性的团队
- 偏好 GraphQL(仅支持 REST/gRPC

Chroma

最适合:
- 本地开发与原型验证
- LangChain/LlamaIndex 集成
- 简单 RAG 概念验证
- 教学项目

应避免:
- 大规模生产负载
- 多租户应用
- 高可用性需求

pgvector

最适合:
- 已有 PostgreSQL 基础设施
- 事务 + 向量在同一数据库
- SQL 原生团队
- 成本优化(无需新增基础设施)

应避免:
- 向量维度超过 2000
- 数十亿级向量(扩展性限制)
- 亚毫秒级延迟需求

Pinecone 设置

from pinecone import Pinecone, ServerlessSpec

# 初始化客户端
pc = Pinecone(api_key="your-api-key")

# 创建无服务器索引
pc.create_index(
    name="rag-index",
    dimension=1536,  # OpenAI ada-002
    metric="cosine",
    spec=ServerlessSpec(
        cloud="aws",
        region="us-east-1"
    )
)

# 获取索引引用
index = pc.Index("rag-index")

# 上传向量及其元数据
index.upsert(
    vectors=[
        {
            "id": "doc-1",
            "values": embedding_vector,
            "metadata": {
                "source": "manual.pdf",
                "page": 42,
                "section": "installation",
                "tenant_id": "acme-corp"
            }
        }
    ],
    namespace="production"
)

# 带元数据过滤的查询
results = index.query(
    vector=query_embedding,
    top_k=10,
    include_metadata=True,
    namespace="production",
    filter={
        "tenant_id": {"$eq": "acme-corp"},
        "section": {"$in": ["installation", "setup"]}
    }
)

# 混合搜索(稀疏-稠密)
from pinecone_text.sparse import BM25Encoder

bm25 = BM25Encoder()
bm25.fit(corpus)  # 在文档集上拟合

results = index.query(
    vector=dense_embedding,
    sparse_vector=bm25.encode_queries(query_text),
    top_k=10,
    alpha=0.5  # 平衡稠密与稀疏权重
)

Weaviate 设置

import weaviate
from weaviate.classes.config import Configure, Property, DataType

# 连接到 Weaviate Cloud
client = weaviate.connect_to_weaviate_cloud(
    cluster_url="https://your-cluster.weaviate.network",
    auth_credentials=weaviate.auth.AuthApiKey("your-api-key")
)

# 或自托管
client = weaviate.connect_to_local(
    host="localhost",
    port=8080
)

# 创建带向量化器的集合
client.collections.create(
    name="Document",
    vectorizer_config=Configure.Vectorizer.text2vec_openai(
        model="text-embedding-3-small"
    ),
    properties=[
        Property(name="content", data_type=DataType.TEXT),
        Property(name="source", data_type=DataType.TEXT),
        Property(name="page", data_type=DataType.INT),
        Property(name="tenant_id", data_type=DataType.TEXT, index_filterable=True)
    ]
)

# 自动向量化插入
documents = client.collections.get("Document")
documents.data.insert(
    properties={
        "content": "Installation guide content...",
        "source": "manual.pdf",
        "page": 42,
        "tenant_id": "acme-corp"
    }
)

# 或使用预计算向量
documents.data.insert(
    properties={"content": "...", "source": "..."},
    vector=precomputed_embedding
)

# 混合搜索(BM25 + 向量)
from weaviate.classes.query import MetadataQuery, Filter

results = documents.query.hybrid(
    query="how to install",
    alpha=0.5,  # 0=仅 BM251=仅向量
    limit=10,
    filters=Filter.by_property("tenant_id").equal("acme-corp"),
    return_metadata=MetadataQuery(score=True, explain_score=True)
)

for obj in results.objects:
    print(f"Score: {obj.metadata.score}, Content: {obj.properties['content'][:100]}")

client.close()

Qdrant 设置

from qdrant_client import QdrantClient
from qdrant_client.models import (
    Distance, VectorParams, PointStruct,
    Filter, FieldCondition, MatchValue,
    PayloadSchemaType
)

# 连接到 Qdrant Cloud
client = QdrantClient(
    url="https://your-cluster.qdrant.io",
    api_key="your-api-key"
)

# 或本地连接
client = QdrantClient(host="localhost", port=6333)

# 创建集合
client.create_collection(
    collection_name="documents",
    vectors_config=VectorParams(
        size=1536,
        distance=Distance.COSINE
    )
)

# 创建负载索引以实现快速过滤
client.create_payload_index(
    collection_name="documents",
    field_name="tenant_id",
    field_schema=PayloadSchemaType.KEYWORD
)

# 上传数据点
client.upsert(
    collection_name="documents",
    points=[
        PointStruct(
            id="doc-1",
            vector=embedding_vector,
            payload={
                "content": "Installation guide...",
                "source": "manual.pdf",
                "page": 42,
                "tenant_id": "acme-corp"
            }
        )
    ]
)

# 带过滤条件的搜索
results = client.search(
    collection_name="documents",
    query_vector=query_embedding,
    limit=10,
    query_filter=Filter(
        must=[
            FieldCondition(
                key="tenant_id",
                match=MatchValue(value="acme-corp")
            )
        ]
    ),
    with_payload=True
)

# 大批量数据上传
from qdrant_client.models import Batch

client.upsert(
    collection_name="documents",
    points=Batch(
        ids=ids_list,
        vectors=vectors_list,
        payloads=payloads_list
    )
)

Chroma 设置

import chromadb
from chromadb.config import Settings

# 持久化本地存储
client = chromadb.PersistentClient(
    path="./chroma_data",
    settings=Settings(anonymized_telemetry=False)
)

# 使用自定义嵌入函数创建集合
from chromadb.utils.embedding_functions import OpenAIEmbeddingFunction

embedding_fn = OpenAIEmbeddingFunction(
    api_key="your-openai-key",
    model_name="text-embedding-3-small"
)

collection = client.get_or_create_collection(
    name="documents",
    embedding_function=embedding_fn,
    metadata={"hnsw:space": "cosine"}
)

# 添加文档(自动嵌入)
collection.add(
    ids=["doc-1", "doc-2"],
    documents=["Installation guide...", "Configuration steps..."],
    metadatas=[
        {"source": "manual.pdf", "page": 42},
        {"source": "manual.pdf", "page": 43}
    ]
)

# 或使用预计算嵌入
collection.add(
    ids=["doc-3"],
    embeddings=[precomputed_vector],
    metadatas=[{"source": "guide.pdf"}],
    documents=["Original text for reference"]
)

# 查询
results = collection.query(
    query_texts=["how to install"],
    n_results=10,
    where={"source": "manual.pdf"},
    include=["documents", "metadatas", "distances"]
)

# 更新已有文档
collection.update(
    ids=["doc-1"],
    documents=["Updated installation guide..."],
    metadatas=[{"source": "manual_v2.pdf", "page": 42}]
)

pgvector 设置

-- 启用扩展
CREATE EXTENSION IF NOT EXISTS vector;

-- 创建含向量列的表
CREATE TABLE documents (
    id SERIAL PRIMARY KEY,
    content TEXT NOT NULL,
    embedding vector(1536),  -- OpenAI 维度
    source VARCHAR(255),
    page INTEGER,
    tenant_id VARCHAR(100),
    created_at TIMESTAMP DEFAULT NOW()
);

-- 创建 HNSW 索引(大多数情况下推荐)
CREATE INDEX ON documents
USING hnsw (embedding vector_cosine_ops)
WITH (m = 16, ef_construction = 64);

-- 或针对超大数据集使用 IVFFlat
CREATE INDEX ON documents
USING ivfflat (embedding vector_cosine_ops)
WITH (lists = 100);

-- 在过滤列上创建索引
CREATE INDEX ON documents (tenant_id);
import psycopg2
from pgvector.psycopg2 import register_vector

conn = psycopg2.connect("postgresql://localhost/ragdb")
register_vector(conn)

# 插入嵌入向量
cur = conn.cursor()
cur.execute(
    """
    INSERT INTO documents (content, embedding, source, page, tenant_id)
    VALUES (%s, %s, %s, %s, %s)
    RETURNING id
    """,
    ("Installation guide...", embedding_vector, "manual.pdf", 42, "acme-corp")
)

# 带过滤条件的相似度搜索
cur.execute(
    """
    SELECT id, content, source, page,
           1 - (embedding <=> %s) AS similarity
    FROM documents
    WHERE tenant_id = %s
    ORDER BY embedding <=> %s
    LIMIT 10
    """,
    (query_embedding, "acme-corp", query_embedding)
)

results = cur.fetchall()

# 使用 pg_trgm 进行混合搜索
cur.execute(
    """
    SELECT id, content,
           (0.5 * (1 - (embedding <=> %s))) +
           (0.5 * similarity(content, %s)) AS hybrid_score
    FROM documents
    WHERE tenant_id = %s
      AND content %% %s  -- Trigram 相似度阈值
    ORDER BY hybrid_score DESC
    LIMIT 10
    """,
    (query_embedding, query_text, "acme-corp", query_text)
)

索引调优指南

HNSW 参数

参数 描述 权衡
m 每个节点的连接数 越大 = 召回率越高,内存占用越大
ef_construction 构建时的搜索宽度 越大 = 索引质量越好,构建越慢
ef_search 查询时的搜索宽度 越大 = 召回率越高,查询越慢
# Qdrant HNSW 调优
client.update_collection(
    collection_name="documents",
    hnsw_config=HnswConfigDiff(
        m=16,                    # 默认值:16,提高召回率可增大
        ef_construct=100,        # 默认值:100,提高索引质量可增大
        full_scan_threshold=10000  # 低于此大小时使用暴力搜索
    )
)

# 查询时 ef 调整
results = client.search(
    collection_name="documents",
    query_vector=query_embedding,
    limit=10,
    search_params=SearchParams(hnsw_ef=128)  # 越大召回率越高
)

量化扩展

# Qdrant 标量量化(内存减少 4 倍)
from qdrant_client.models import ScalarQuantization, ScalarQuantizationConfig

client.update_collection(
    collection_name="documents",
    quantization_config=ScalarQuantization(
        scalar=ScalarQuantizationConfig(
            type="int8",
            quantile=0.99,
            always_ram=True
        )
    )
)

多租户模式

命名空间隔离(Pinecone

# 不同命名空间中的租户数据
index.upsert(vectors=[...], namespace="tenant-acme")
index.upsert(vectors=[...], namespace="tenant-globex")

# 在租户命名空间内查询
results = index.query(
    vector=query_embedding,
    namespace="tenant-acme",
    top_k=10
)

元数据过滤(Qdrant/Weaviate

# 为所有文档添加 tenant_id
point = PointStruct(
    id="doc-1",
    vector=embedding,
    payload={"tenant_id": "acme", "content": "..."}
)

# 始终按租户过滤
results = client.search(
    collection_name="documents",
    query_vector=query_embedding,
    query_filter=Filter(
        must=[FieldCondition(key="tenant_id", match=MatchValue(value="acme"))]
    )
)

每租户独立集合(高隔离性)

# 创建租户专属集合
client.create_collection(
    collection_name=f"docs_{tenant_id}",
    vectors_config=VectorParams(size=1536, distance=Distance.COSINE)
)

决策流程图

开始
  │
  ├─ 需要托管服务且零运维?
  │   └─ 是 → Pinecone
  │
  ├─ 已有 PostgreSQL
  │   └─ 是 → pgvector(若向量维度 < 2000)
  │
  ├─ 需要内置向量化?
  │   └─ 是 → Weaviate
  │
  ├─ 需要极致性能 + 自托管?
  │   └─ 是 → Qdrant
  │
  ├─ 原型开发 / 本地开发?
  │   └─ 是 → Chroma
  │
  └─ 默认推荐 → Qdrant(功能与性能的平衡)

快速参考

任务 Pinecone Weaviate Qdrant pgvector
创建索引/集合 create_index() collections.create() create_collection() CREATE TABLE
插入 upsert() data.insert() upsert() INSERT
搜索 query() query.near_vector() search() ORDER BY <=>
过滤 filter={} Filter.by_property() query_filter=Filter() WHERE
删除 delete() data.delete_by_id() delete() DELETE
混合搜索 sparse_vector 参数 query.hybrid() sparse vectors 手动实现

相关技能

  • 数据库优化器 - 索引调优与查询性能
  • 云架构师 - 向量数据库托管的基础设施决策
  • Python 专家 - 异步客户端的实现模式