为什么在 SQL 里做混合
pgvector 的独特优势是向量近邻与关系条件写在同一句 SQL 里:WHERE 过滤、JOIN 业务表、全文检索(tsvector)都能与向量排序组合,一条语句完成多条件召回。省掉了「向量库与业务库之间对账」的麻烦,也能直接复用已有的权限控制与事务能力,适合文档量中等、已有 PostgreSQL 技术栈的团队。
基本信息
| 前提 | PostgreSQL 安装 pgvector 扩展,向量列类型为 vector |
|---|---|
| 距离操作符 | <-> 表示 L2,<=> 表示余弦,<#> 表示内积 |
| 混合方式 | 先过滤或先关键词检索缩小候选,再按向量距离排序 |
| 性能关键 | 过滤条件的选择性,以及向量索引是否被正确命中 |
典型使用场景
- 权限与状态过滤:只检索已发布且在有效期内、用户有权限的文档
- 与业务表联动:JOIN 文档主表取标题与链接,回答里直接展示来源
- 中文关键词补充:型号与错误码用全文检索精确命中,语义问题交给向量
- 一次开发两用:同一套 SQL 既做后台检索,也做在线问答的召回
- 小规模团队选型:不引入独立向量库即可支撑十万级切片
过滤与向量排序
过滤与向量排序
SELECT c.id, c.content
FROM kb_chunks c
JOIN kb_docs d ON d.id = c.doc_id -- 关联业务表取权限与状态
WHERE d.status = 'published'
AND d.updated_at >= now() - interval '90 days'
ORDER BY c.embedding <=> $1 -- 余弦距离,越小越相似
LIMIT 10;
-- 过滤条件选择性高时,数据库会先做过滤再排序,效率通常更好
全文检索两段式
全文检索两段式
WITH kw AS (
SELECT id FROM kb_chunks
WHERE to_tsvector('simple', content) @@ plainto_tsquery('simple', $2)
LIMIT 50 -- 先缩候选,避免全表向量比较
)
SELECT c.id FROM kb_chunks c
WHERE c.id IN (SELECT id FROM kw)
ORDER BY c.embedding <=> $1 LIMIT 10;
两种两段式写法
| 写法 | 执行顺序 | 适用情况 |
|---|---|---|
| 过滤加向量排序 | 先按条件过滤再排序 | 过滤选择性高、候选集小 |
| 全文检索加向量排序 | 先关键词缩候选再向量排序 | 型号、错误码等专有名词查询 |
| 子查询内排序再过滤 | 排序后过滤,语义错误 | 不推荐,会漏掉应命中结果 |
| JOIN 业务表 | 按权限与状态过滤 | 需与业务状态联动的场景 |
过滤条件的选择性决定执行计划:高选择性过滤先行、再做向量排序通常更划算,必要时用 EXPLAIN 确认索引有没有被用上。
用 EXPLAIN 或 EXPLAIN ANALYZE 看计划,比凭感觉调 SQL 可靠:能看到是全表扫描还是走了索引,也能看到过滤实际剩多少行。