AI 基础 | | 约 18 分钟 | 7,138 字

向量数据库入门:从原理到选型

对比 Pinecone、Milvus、Chroma、Weaviate 等主流向量数据库的特点与适用场景

为什么需要向量数据库

上一篇我们聊了 Embedding,知道了文本可以变成向量。但问题来了——当你有 100 万条文档,每条都是 1536 维的向量,你怎么快速找到跟用户查询最相似的那几条?

暴力搜索?遍历 100 万条向量,每条做一次余弦相似度计算。可以,但太慢了。

# 暴力搜索 - O(n) 复杂度
for doc in all_documents:  # 100 万次循环
    similarity = cosine_similarity(query_vector, doc.vector)  # 1536 维点积

这就是向量数据库要解决的核心问题:在海量向量中快速找到最相似的 Top-K。


传统数据库为什么不行

特性传统数据库 (MySQL/PostgreSQL)向量数据库
数据类型结构化数据(行、列)高维向量
查询方式精确匹配 (WHERE id = 1)近似最近邻 (ANN)
索引类型B-Tree、HashHNSW、IVF、PQ
相似度搜索不原生支持核心功能
百万级搜索延迟秒级(全表扫描)毫秒级

当然,PostgreSQL 有 pgvector 扩展可以做向量搜索,SQLite 也有类似方案。对于小规模数据(几十万条以内),这些方案完全够用。但当数据量上去之后,专用向量数据库的优势就体现出来了。


向量搜索的核心:ANN 算法

ANN (Approximate Nearest Neighbor) 是向量搜索的核心。它不追求找到绝对最近的邻居,而是用极小的精度损失换取巨大的速度提升。

HNSW (Hierarchical Navigable Small World)

目前最主流的 ANN 算法。想象一个多层的图结构:

第 3 层 (最稀疏):  A -------- D
                   |          |
第 2 层:           A --- B -- D
                   |    |     |
第 1 层:           A-B--C-D-E-F
                   | |  | | | |
第 0 层 (最密集):  A-B-C-D-E-F-G-H-I-J

搜索时从最高层开始,快速定位到大致区域,然后逐层下降,越来越精确。就像先看世界地图找到国家,再看省级地图找到城市,最后看街道地图找到具体位置。

特点

  • 搜索速度快,O(log n)
  • 内存占用较高(需要存储图结构)
  • 支持动态插入和删除
  • 大多数向量数据库的默认选择

IVF (Inverted File Index)

先把向量空间划分成若干个聚类(Voronoi 区域),搜索时只在最近的几个聚类中查找:

聚类 1: [v1, v5, v8, v12, ...]
聚类 2: [v2, v3, v9, v15, ...]
聚类 3: [v4, v6, v7, v11, ...]
...

查询 q → 找到最近的聚类 2 和 3 → 只在这两个聚类中搜索

特点

  • 需要预先训练聚类中心
  • 内存占用较低
  • 适合静态数据集
  • 可以和 PQ 结合进一步压缩

PQ (Product Quantization)

把高维向量切分成多个子空间,每个子空间独立量化压缩:

原始向量 (1536 维):
[0.21, -0.45, 0.78, ..., 0.33]

切分为 192 个子空间,每个 8 维:
[0.21, -0.45, ...] [0.78, 0.12, ...] ... [0.33, -0.11, ...]

每个子空间量化为一个 ID:
[42] [17] ... [89]

压缩比: 1536 × 4 bytes → 192 × 1 byte = 32x 压缩

特点

  • 极大减少内存占用
  • 有一定精度损失
  • 通常和 IVF 配合使用 (IVF-PQ)

主流向量数据库对比

一览表

数据库类型开源托管服务适合场景ANN 算法
Pinecone云原生生产环境,不想运维自研
Milvus分布式Zilliz Cloud大规模生产环境HNSW, IVF, PQ
Chroma嵌入式原型开发,小规模HNSW
Weaviate分布式需要混合搜索HNSW
Qdrant分布式高性能,Rust 编写HNSW
pgvector扩展随 PG已有 PostgreSQL 基础设施IVF, HNSW

Pinecone

优点:
✓ 全托管,零运维
✓ 自动扩缩容
✓ Serverless 模式按用量计费

缺点:
✗ 不开源,供应商锁定
✗ 自定义能力有限
✗ 数据必须存在 Pinecone 的云上

Milvus

优点:
✓ 开源,社区活跃
✓ 支持多种索引类型
✓ 分布式架构,支持十亿级向量
✓ 有托管服务 Zilliz Cloud

缺点:
✗ 部署和运维相对复杂
✗ 资源消耗较大

Chroma

优点:
✓ 极简 API,几行代码就能用
✓ 嵌入式模式,无需额外服务
✓ 和 LangChain/LlamaIndex 集成好
✓ 适合快速原型开发

缺点:
✗ 不适合大规模生产
✗ 功能相对简单

Weaviate

优点:
✓ 内置向量化模块(可以自动 Embedding)
✓ 支持混合搜索(向量 + 关键词)
✓ GraphQL API
✓ 多租户支持

缺点:
✗ 学习曲线稍陡
✗ 内存占用较高

Qdrant

优点:
✓ Rust 编写,性能优秀
✓ 支持丰富的过滤条件
✓ 内存和磁盘混合存储
✓ API 设计简洁

缺点:
✗ 生态相对年轻
✗ 社区规模较小

实战:用 Chroma 构建语义搜索

Chroma 是最适合入门的向量数据库。我们来用它构建一个简单的语义搜索系统。

安装

pip install chromadb openai

基本用法

import chromadb
from openai import OpenAI

# 创建 Chroma 客户端(内存模式)
chroma_client = chromadb.Client()

# 创建一个 collection(类似数据库中的表)
collection = chroma_client.create_collection(
    name="my_docs",
    metadata={"hnsw:space": "cosine"}  # 使用余弦相似度
)

# 准备文档
documents = [
    "Python 是一门简洁优雅的编程语言,适合初学者入门",
    "JavaScript 是 Web 开发的核心语言,前后端都能用",
    "Rust 以内存安全和高性能著称,适合系统编程",
    "机器学习是人工智能的一个分支,通过数据训练模型",
    "深度学习使用神经网络处理复杂的模式识别任务",
    "Docker 是一种容器化技术,简化了应用部署流程",
]

# 添加文档(Chroma 可以自动生成 Embedding)
collection.add(
    documents=documents,
    ids=[f"doc_{i}" for i in range(len(documents))]
)

# 搜索
results = collection.query(
    query_texts=["如何学习编程"],
    n_results=3
)

print("搜索结果:")
for doc, distance in zip(results["documents"][0], results["distances"][0]):
    print(f"  [{distance:.4f}] {doc}")

使用 OpenAI Embedding

import chromadb
from chromadb.utils import embedding_functions

# 使用 OpenAI 的 Embedding 模型
openai_ef = embedding_functions.OpenAIEmbeddingFunction(
    api_key="your-api-key",
    model_name="text-embedding-3-small"
)

# 创建 collection 时指定 Embedding 函数
collection = chroma_client.create_collection(
    name="my_docs_openai",
    embedding_function=openai_ef
)

# 后续用法完全一样
collection.add(
    documents=documents,
    ids=[f"doc_{i}" for i in range(len(documents))]
)

持久化存储

# 使用持久化客户端,数据存到磁盘
chroma_client = chromadb.PersistentClient(path="./chroma_data")

# 之后的用法完全一样
# 重启程序后数据还在

带元数据过滤

# 添加文档时附带元数据
collection.add(
    documents=["Python 入门教程", "Python 高级技巧", "Java 入门教程"],
    metadatas=[
        {"language": "python", "level": "beginner"},
        {"language": "python", "level": "advanced"},
        {"language": "java", "level": "beginner"}
    ],
    ids=["doc_0", "doc_1", "doc_2"]
)

# 搜索时过滤
results = collection.query(
    query_texts=["编程入门"],
    n_results=3,
    where={"language": "python"}  # 只搜索 Python 相关的
)

选型指南:该用哪个

按项目阶段选

原型开发 / 个人项目
  → Chroma(嵌入式,零配置)

中小规模生产(< 100 万向量)
  → Qdrant 或 Weaviate(单机部署)
  → pgvector(如果已有 PostgreSQL)

大规模生产(> 1000 万向量)
  → Milvus(分布式,开源)
  → Pinecone(托管,省心)

不想运维
  → Pinecone Serverless
  → Zilliz Cloud (Milvus 托管版)
  → Weaviate Cloud

按功能需求选

需求推荐
快速原型Chroma
混合搜索(向量 + 关键词)Weaviate
极致性能Qdrant
大规模分布式Milvus
零运维Pinecone
已有 PostgreSQLpgvector
多租户Weaviate, Qdrant

与 LLM 应用的集成

向量数据库在 LLM 应用中最常见的角色是 RAG 的检索层:

用户提问

Embedding 模型 → 查询向量

向量数据库 → 检索相关文档

LLM + 相关文档 → 生成回答

主流框架都有很好的集成:

# LangChain + Chroma
from langchain_community.vectorstores import Chroma
from langchain_openai import OpenAIEmbeddings

vectorstore = Chroma.from_documents(
    documents=docs,
    embedding=OpenAIEmbeddings()
)

retriever = vectorstore.as_retriever(search_kwargs={"k": 3})
results = retriever.invoke("什么是向量数据库")
# LlamaIndex + Chroma
from llama_index.core import VectorStoreIndex
from llama_index.vector_stores.chroma import ChromaVectorStore

vector_store = ChromaVectorStore(chroma_collection=collection)
index = VectorStoreIndex.from_vector_store(vector_store)
query_engine = index.as_query_engine()
response = query_engine.query("什么是向量数据库")

性能优化建议

1. 选择合适的索引类型

数据量 < 10 万: 暴力搜索 (Flat) 就够了
数据量 10 万 - 1000 万: HNSW
数据量 > 1000 万: IVF-PQ 或 HNSW + PQ

2. 调整 HNSW 参数

# Milvus 示例
index_params = {
    "index_type": "HNSW",
    "metric_type": "COSINE",
    "params": {
        "M": 16,           # 每个节点的连接数,越大越精确但越慢
        "efConstruction": 200  # 构建时的搜索宽度
    }
}

3. 合理使用过滤

先过滤再搜索(pre-filtering)比先搜索再过滤(post-filtering)更高效,但不是所有数据库都支持。Qdrant 和 Weaviate 在这方面做得比较好。

4. 批量操作

# 好的做法:批量插入
collection.add(
    documents=all_documents,  # 一次性插入
    ids=all_ids
)

# 不好的做法:逐条插入
for doc, id in zip(all_documents, all_ids):
    collection.add(documents=[doc], ids=[id])  # 每次一条,很慢

总结

向量数据库是 AI 应用的基础设施。选择时不必纠结”最好的”,而是选”最适合当前阶段的”:

  • 刚开始探索?用 Chroma,几行代码就能跑
  • 准备上生产?评估 Qdrant、Weaviate 或 Milvus
  • 不想操心运维?Pinecone 或各家的云服务

向量数据库让 AI 拥有了”记忆”。有了它,我们的 LLM 应用才能从”只会聊天”进化到”真正有用”。下一篇我们来聊 RAG——把向量数据库和 LLM 串起来的完整架构。

评论

加载中...

相关文章

分享:

评论

加载中...