Files
zhuangang/topics/ai/vector-db/02-selection-pgvector.md
T

88 lines
4.9 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
---
id: ai.vector-db.selection-pgvector
title: 向量库选型和 pgvector 实战:Chroma / pgvector / Milvus / Elasticsearch
type: lesson
domain: ai
stack: [vector-db, postgresql]
tags: [向量库选型, pgvector, Chroma, Milvus, Elasticsearch, 元数据过滤]
level: intermediate
prerequisites: [ai.vector-db.ann-metrics]
est_hours: 3
related: [ai.vector-db.scenario.multi-tenant-index, backend.postgresql.index, backend.elasticsearch.index]
week: [5, 6]
order: 2
---
# 向量库选型和 pgvector 实战:Chroma / pgvector / Milvus / Elasticsearch
## 解释说明
### 选型对比
| 方案 | 适合 | 优点 | 注意 |
| --- | --- | --- | --- |
| **Chroma** | 原型、学习、小规模 | 安装即用,Python 内嵌模式 | 大规模、高可用要评估;版本间 API 有变化 |
| **pgvector**(PostgreSQL 扩展) | 已有 PostgreSQL、百万级以内、需要和业务数据联查 | 一套数据库;SQL 过滤、事务、备份都复用 | 超大规模和高 QPS 时不如专用向量库;向量索引的内存占用要规划 |
| **Milvus** | 千万到亿级、需要分布式 | 多种索引、分区、标量过滤、水平扩展 | 组件多,运维成本高(也有托管版) |
| **Elasticsearch / OpenSearch** | 已经用 ES 做全文检索,想要关键词 + 向量混合检索 | 一个引擎做 BM25 + kNN | 向量功能的版本差异较大,以官方文档为准 |
| FAISS | 嵌入到程序里的向量检索库 | 快,索引类型全 | 是库不是数据库:没有持久化服务、过滤、权限,需要自己做 |
**本计划的选择**:学习阶段用 Chroma 或 numpy 快速理解;项目使用 **pgvector**,因为第 3~4 周已经学了 PostgreSQL,业务数据、权限和向量可以放在同一个库里联查;面试时能讲清楚“为什么不用 Milvus”和“什么规模需要换”。
### pgvector 要点(以官方文档为准:https://github.com/pgvector/pgvector)
- 类型:`vector(n)`;还有 `halfvec`(半精度,省一半空间)、`sparsevec`。
- 运算符:`<->` L2 距离,`<#>` **负**内积,`<=>` 余弦距离(都是越小越近)。
- 索引:`USING hnsw (embedding vector_cosine_ops)`,运算符类必须和查询用的运算符一致(`vector_l2_ops` / `vector_ip_ops` / `vector_cosine_ops`),否则不走索引。
- 查询参数:`SET hnsw.ef_search = 100;`(默认 40);IVFFlat 用 `ivfflat.probes`。
- 过滤:`WHERE tenant_id = $1 ORDER BY embedding <=> $2 LIMIT 10`。过滤条件很严格时,0.8 版本可以开启 `hnsw.iterative_scan` 让索引继续扫描直到凑够结果;或者按租户建部分索引 / 分区。
## 案例
一个 SaaS 客服系统,50 个租户共 200 万个知识块,平均每个租户 4 万,最大租户 60 万。业务表已经在 PostgreSQL 中。选择 pgvector:块表带 `tenant_id`,HNSW 索引 + `tenant_id` 普通索引;大租户检索结果不足时开启迭代扫描。评估结论写进文档:当总量超过数千万或 QPS 超过单机能力时,再评估 Milvus。
## 代码示例
pgvector 的表结构和查询(完整可运行版本 [examples/vector-stores/pgvector_demo.py](examples/vector-stores/pgvector_demo.py),已在 PostgreSQL 17 + pgvector 0.8.0 上运行):
```sql
CREATE EXTENSION IF NOT EXISTS vector;
CREATE TABLE chunks (
id BIGSERIAL PRIMARY KEY,
tenant_id TEXT NOT NULL,
doc_id TEXT NOT NULL,
version INT NOT NULL,
content TEXT NOT NULL,
embedding vector(1024) NOT NULL
);
CREATE INDEX ON chunks USING hnsw (embedding vector_cosine_ops);
CREATE INDEX ON chunks (tenant_id);
CREATE INDEX ON chunks (doc_id);
-- 查询:$1 租户,$2 查询向量
SET hnsw.ef_search = 100;
SELECT id, doc_id, content, 1 - (embedding <=> $2) AS similarity
FROM chunks
WHERE tenant_id = $1
ORDER BY embedding <=> $2
LIMIT 10;
```
Chroma 的写入、元数据过滤、更新删除见 [examples/vector-stores/chroma_demo.py](examples/vector-stores/chroma_demo.py)。
## 易错点
- 建索引用了 `vector_l2_ops`,查询用 `<=>`:不走索引,变成全表扫描。
- `<#>` 返回的是负内积,排序时直接 `ORDER BY embedding <#> q` 就是内积从大到小;自己再加负号就反了。
- 小表的执行计划显示顺序扫描:数据少时规划器认为顺序扫描更便宜,这是正常的,不是索引失效。
- HNSW 索引默认不支持太高的维度(`vector` 类型的索引上限 2000 维,`halfvec` 4000 维,以官方文档为准),高维模型要选 `halfvec` 或降维。
- 大批量导入时边写边维护 HNSW 索引很慢:先导入再建索引,并适当调大 `maintenance_work_mem`。
- Chroma 不同版本的客户端 / 持久化格式有变化,升级前看迁移说明。
## 面试常问
- 为什么选 pgvector 而不是 Milvus?什么时候要换?
- pgvector 的三种距离运算符分别是什么?索引怎么建才能生效?
- 向量和业务数据放一个库有什么好处和风险?