乐于分享
好东西不私藏

Day 29|pgvector:AI 时代的 PostgreSQL

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)。推荐配合 LangChainLlamaIndex,它们都内置了 pgvector 支持,几行代码就能搭起完整的 RAG pipeline。如果你的 AI 应用数据量不超过千万级,pgvector 完全够用,不需要引入 Pinecone、Weaviate 等专用向量数据库,少一个系统少一堆烦恼。


💡 今日一句话总结
pgvector支持存储高维向量,cosine/L2相似度搜索,配合HNSW索引,是AI应用RAG的首选存储。

📅 明天预告:Day 30|30天 PG 学习路线图 —— 从入门到大神,你已经走了多远?🗺️

觉得有收获?👇 点赞 + 在看,让更多人认识这头大象 🐘
每天 3 分钟,30 天入门 PostgreSQL  |  关注不迷路,明天见!