Day 29|pgvector:AI 时代的 PostgreSQL
🐘 每天一个PG知识点 · Day 29 · 学习路线
pgvector:AI 时代的 PostgreSQL
ChatGPT 的记忆系统,可能就存在 PostgreSQL 里 🤖
📖 预计阅读时间:5 分钟 | 难度:⭐⭐⭐☆☆ 零基础友好
2023年底,某家做企业知识库的创业公司遇到了一个问题:他们用 Python 写了一个 RAG 系统(让 AI 能回答关于公司文档的问题),向量存在 Pinecone(一个专门的向量数据库),业务数据存在 PostgreSQL。
两个数据库,两套维护成本,跨库查询还要在代码层做关联,开发体验很割裂。
后来他们发现了 pgvector——PostgreSQL 的向量扩展。把向量搜索迁回 PostgreSQL,只需要一个数据库,关联查询直接 JOIN,事务支持全有,还省掉了 Pinecone 的月费。
这不是个例。越来越多的 AI 应用开发者正在用 pgvector 替代专门的向量数据库——因为「够用」加「省事」,往往比「专业」更有价值。
🧠 向量是什么?为什么 AI 需要它?
先搞懂背景概念。
AI 大模型处理文本时,会把每段文字转换成一个高维数字数组——这就是向量(Embedding)。比如 OpenAI 的 text-embedding-ada-002 模型,会把一段话变成一个长度为 1536 的浮点数数组:
"PostgreSQL 是一个开源数据库" → [0.0234, -0.1823, 0.5671, 0.0089, ..., -0.2341] -- 1536个数字 "PG是最受欢迎的关系型数据库之一" → [0.0198, -0.1756, 0.5489, 0.0102, ..., -0.2198] -- 1536个数字
这两个向量在 1536 维空间里方向非常接近(余弦相似度高),因为它们讲的是同一件事。这种「语义相近 = 向量相近」的特性,是 AI 语义搜索的核心原理。
传统数据库只会精确匹配文字,搜索「PostgreSQL 数据库」找不到「PG」。向量搜索找的是语义相近的内容,这就是 AI 时代的搜索革命。
🐘 pgvector 能做什么?
pgvector 是 PostgreSQL 的开源扩展,给它增加了:
• 新数据类型:vector(n),存储 n 维浮点向量
• 三种相似度计算:余弦相似度、欧氏距离、内积
• 两种索引:IVFFlat(内存友好)和 HNSW(查询更快)
• 完整的 SQL 支持:可以和其他列 JOIN、WHERE 过滤、事务保障
💻 从零搭建一个语义搜索系统
来写一个完整的例子——给公司文档建语义搜索:
第1步:安装扩展,建表
-- 安装 pgvector 扩展(只需一次)
CREATE EXTENSION IF NOT EXISTS vector;
-- 创建文档表
CREATE TABLE documents (
id SERIAL PRIMARY KEY,
title TEXT NOT NULL,
content TEXT NOT NULL,
category TEXT,
created_at TIMESTAMP DEFAULT NOW(),
embedding vector(1536) -- OpenAI ada-002 维度
);
-- 创建 HNSW 索引(查询更快,推荐)
-- m=16 是图连接数,ef_construction=64 是构建时搜索深度
CREATE INDEX ON documents USING hnsw (embedding vector_cosine_ops)
WITH (m = 16, ef_construction = 64);
第2步:Python 写入向量
import psycopg2
from openai import OpenAI
client = OpenAI()
def get_embedding(text):
# 调用 OpenAI 把文本转成向量
response = client.embeddings.create(
model="text-embedding-ada-002",
input=text
)
return response.data[0].embedding
def insert_document(conn, title, content, category):
# 插入一篇文档,同时存向量
embedding = get_embedding(content)
with conn.cursor() as cur:
cur.execute(
"INSERT INTO documents (title, content, category, embedding)"
" VALUES (%s, %s, %s, %s)",
(title, content, category, embedding)
)
conn.commit()
# 批量插入公司文档
conn = psycopg2.connect("postgresql://user:pass@localhost/mydb")
insert_document(conn, "请假流程", "员工请假需要提前3天申请...", "HR政策")
insert_document(conn, "报销规定", "差旅报销需要上传发票...", "财务规定")
第3步:语义搜索
def semantic_search(conn, query, limit=5):
# 语义搜索:找出和问题最相关的文档
query_embedding = get_embedding(query)
with conn.cursor() as cur:
cur.execute(
"SELECT title, content, category,"
" 1 - (embedding <=> %s::vector) AS similarity"
" FROM documents"
" ORDER BY embedding <=> %s::vector"
" LIMIT %s",
(query_embedding, query_embedding, limit)
)
return cur.fetchall()
# 搜索:即使文档里没有这句话,也能找到「请假流程」
results = semantic_search(conn, "我想请两天假怎么办?")
for title, content, category, similarity in results:
print(f"[相似度:{similarity:.3f}] {title} ({category})")
第4步:结合 SQL 过滤(pgvector 的杀手锏)
-- 只在 HR 类文档里搜索,还能 JOIN 用户表、过滤权限
SELECT d.title, d.content,
1 - (d.embedding <=> query_vec) AS similarity
FROM documents d
WHERE d.category = 'HR政策' -- 普通 SQL 过滤
AND d.created_at > '2026-01-01' -- 只看今年的文档
ORDER BY d.embedding <=> query_vec -- 向量相似度排序
LIMIT 5;
-- 这种「向量搜索 + SQL过滤」在纯向量数据库里很难做到
-- pgvector 让它变成一行 WHERE 子句
🎯 三种相似度计算,怎么选?
-- <=> 余弦距离(值越小越相似,0=完全相同,2=完全相反) -- 适合:文本语义搜索(最常用) SELECT * FROM docs ORDER BY embedding <=> query_vec LIMIT 5; -- <-> 欧氏距离(L2,值越小越相似) -- 适合:图像特征、数值型向量 SELECT * FROM docs ORDER BY embedding <-> query_vec LIMIT 5; -- <#> 内积(负值,越小越相似) -- 适合:已经归一化的向量,性能略优于余弦 SELECT * FROM docs ORDER BY embedding <#> query_vec LIMIT 5;
文本语义搜索 99% 的情况用 <=>(余弦距离)就对了。
⚡ IVFFlat vs HNSW:两种索引怎么选?
向量搜索如果不加索引,每次查询要和所有向量逐一计算距离——百万条数据会非常慢。索引用近似算法加速,以少量精度损失换取极大的速度提升:
-- IVFFlat(倒排文件索引)
-- 把向量分成 N 个簇,查询时只搜最近的几个簇
-- 优点:内存占用小,构建快
-- 缺点:召回率略低(约90-95%)
-- 适合:数据量大、内存有限的场景
CREATE INDEX ON documents USING ivfflat (embedding vector_cosine_ops)
WITH (lists = 100); -- lists 约等于 sqrt(行数)
-- HNSW(分层可导航小世界图)
-- 构建层级图结构,查询时沿图跳跃逼近目标
-- 优点:查询更快,召回率更高(约99%)
-- 缺点:内存占用大(约是向量数据的2-3倍),构建慢
-- 适合:数据量 < 500万、对查询速度要求高的场景
CREATE INDEX ON documents USING hnsw (embedding vector_cosine_ops)
WITH (m = 16, ef_construction = 64);
数据量 < 100万行?用 HNSW,查询更快。数据量更大或内存有限?用 IVFFlat。
⚠️ 常见踩坑 / 误区
坑1:插入向量前没建索引,后来再建很慢
数据量大时,建索引需要对所有向量做聚类/建图,百万行可能要几分钟甚至更长。建议在数据量不太大时就建好索引(CONCURRENTLY 建索引不锁表),或者在批量导入完成后一次性建。
坑2:向量维度不固定,用不同模型生成的向量混存vector(1536) 是严格的 1536 维,换成 text-embedding-3-large(3072维)直接报错。一张表只能存一种维度的向量,不同模型的向量要分表存。
坑3:把相似度搜索和精确过滤顺序搞反
先向量搜索再 SQL 过滤和先 SQL 过滤再向量搜索结果完全不同!正确做法是先 WHERE 缩小候选集,再按向量排序取 TOP-N,这样又快又准。
🚀 进阶延伸
pgvector + PostgreSQL 是目前搭建 RAG(检索增强生成) 系统最省心的方案:向量存 pgvector、结构化业务数据同库存、metadata 过滤直接 WHERE、权限控制复用 PG 行级安全(RLS)。推荐配合 LangChain 或 LlamaIndex,它们都内置了 pgvector 支持,几行代码就能搭起完整的 RAG pipeline。如果你的 AI 应用数据量不超过千万级,pgvector 完全够用,不需要引入 Pinecone、Weaviate 等专用向量数据库,少一个系统少一堆烦恼。
💡 今日一句话总结
pgvector支持存储高维向量,cosine/L2相似度搜索,配合HNSW索引,是AI应用RAG的首选存储。
📅 明天预告:Day 30|30天 PG 学习路线图 —— 从入门到大神,你已经走了多远?🗺️
觉得有收获?👇 点赞 + 在看,让更多人认识这头大象 🐘
每天 3 分钟,30 天入门 PostgreSQL | 关注不迷路,明天见!
夜雨聆风