欢迎光临
我们一直在努力

如何利用 PostgreSQL pgvector 扩展实现高效的向量相似度搜索

在向量搜索领域,Faiss、Milvus、Elasticsearch 等专用引擎占据主流,但对于许多中小规模应用场景,引入一套全新的向量数据库意味着额外的运维成本和架构复杂度。PostgreSQL 作为最广泛使用的关系型数据库之一,通过 pgvector 扩展即可原生支持向量存储与相似度检索,让你在现有数据库架构上零成本扩展出向量搜索能力。

本文将从安装配置、数据建模、索引选择到查询优化,手把手教你用 pgvector 构建生产可用的向量检索方案。

数据库技术

pgvector 安装与启用

pgvector 以 PostgreSQL 扩展的形式安装,支持 PostgreSQL 12 及以上版本。以 Ubuntu 为例,安装步骤如下:

# 安装 pgvector 扩展
sudo apt install postgresql-16-pgvector

# 连接数据库并启用扩展
psql -U postgres -d mydb -c "CREATE EXTENSION IF NOT EXISTS vector;"

安装完成后,即可在数据库中使用 vector 数据类型。验证是否成功:

SELECT * FROM pg_extension WHERE extname = 'vector';

表结构设计与数据写入

pgvector 提供了 vector 类型来存储固定维度的浮点向量。以下是一个典型的文档语义检索场景的建表方案:

CREATE TABLE documents (
    id SERIAL PRIMARY KEY,
    title TEXT NOT NULL,
    content TEXT NOT NULL,
    embedding vector(768) NOT NULL,
    created_at TIMESTAMPTZ DEFAULT NOW()
);

向量维度需要与你使用的 Embedding 模型输出维度一致。常见的维度有:

  • OpenAI text-embedding-3-small: 1536 维
  • BGE-large-zh: 1024 维
  • sentence-transformers/all-MiniLM-L6-v2: 384 维
  • 通用 768 维模型(如 text-embedding-ada-002)

插入数据时,直接将 Python list 转换为 vector 字符串即可:

import psycopg2
import numpy as np

conn = psycopg2.connect(host="localhost", dbname="mydb", user="postgres")
cur = conn.cursor()

# 假设 embedding 是模型输出的 768 维向量
embedding = np.random.randn(768).tolist()
embedding_str = "[" + ",".join(f"{x:.6f}" for x in embedding) + "]"

cur.execute(
    "INSERT INTO documents (title, content, embedding) VALUES (%s, %s, %s::vector)",
    ("示例文档", "这是一段测试内容", embedding_str)
)
conn.commit()

代码编程

相似度查询与距离函数

pgvector 支持三种距离度量方式,适用于不同的搜索场景:

  • L2 距离<->):欧氏距离,适合图像特征匹配
  • 内积<#>):负内积,适合已归一化的向量
  • 余弦距离<=>):1 – 余弦相似度,最常用于文本语义搜索

执行一次 Top-K 余弦相似度检索:

-- 查询与目标向量最相似的 10 篇文档
SELECT id, title, 1 - (embedding <=> $1::vector) AS similarity
FROM documents
ORDER BY embedding <=> $1::vector
LIMIT 10;

在 Python 中执行查询的完整示例:

import psycopg2

def search_similar(query_embedding: list, top_k: int = 10):
    conn = psycopg2.connect(host="localhost", dbname="mydb", user="postgres")
    cur = conn.cursor()

    embedding_str = "[" + ",".join(f"{x:.6f}" for x in query_embedding) + "]"

    cur.execute("""
        SELECT id, title, 1 - (embedding <=> %s::vector) AS similarity
        FROM documents
        ORDER BY embedding <=> %s::vector
        LIMIT %s
    """, (embedding_str, embedding_str, top_k))

    results = cur.fetchall()
    conn.close()
    return results

索引类型与性能优化

当数据量超过几千条时,暴力全表扫描会变得很慢。pgvector 提供了两种索引来加速搜索:

IVFFlat 索引适合中等规模数据集(几十万条),基于倒排文件思想将向量聚类分桶:

-- 先创建索引,lists 参数建议设为 rows/1000 的平方根
CREATE INDEX ON documents USING ivfflat (embedding vector_cosine_ops)
WITH (lists = 100);

-- 查询时设置探查的桶数量,越大召回率越高但越慢
SET ivfflat.probes = 10;

HNSW 索引是 pgvector 0.5+ 新增的图结构索引,在召回率和查询速度上都优于 IVFFlat,推荐生产使用:

-- HNSW 索引,m 和 ef_construction 控制图的密度
CREATE INDEX ON documents USING hnsw (embedding vector_cosine_ops)
WITH (m = 16, ef_construction = 200);

-- 查询时设置搜索宽度
SET hnsw.ef_search = 40;

数据图表分析

混合检索:向量搜索与条件过滤结合

pgvector 最大的优势在于可以与 SQL 的 WHERE 条件无缝结合,实现向量搜索与结构化过滤的混合查询,这在专用向量数据库中往往需要额外的预过滤机制:

-- 只搜索最近 30 天的文档,按类别过滤后取 Top-5
SELECT id, title, 1 - (embedding <=> $1::vector) AS similarity
FROM documents
WHERE created_at > NOW() - INTERVAL '30 days'
  AND title LIKE '%机器学习%'
ORDER BY embedding <=> $1::vector
LIMIT 5;

实际生产中建议将过滤条件与 HNSW 索引配合使用。PostgreSQL 的查询规划器会自动决定先走索引还是先过滤,通常对高选择性条件先过滤再走向量索引效果更好。

总结

pgvector 为 PostgreSQL 带来了实用的向量搜索能力,其核心优势在于:

  • 零额外基础设施:无需引入新的数据库组件,直接复用现有 PG 集群
  • SQL 原生集成:向量检索与关系查询、事务、权限管理天然结合
  • HNSW 索引:百万级数据量下仍可保持毫秒级响应
  • 运维简单:备份、主从复制、监控等 PG 生态工具完全适用

对于数据量在千万级以下、团队已有 PostgreSQL 运维经验的场景,pgvector 是性价比最高的向量搜索方案。当数据规模突破亿级或需要极致的检索性能时,再考虑迁移到 Faiss 或 Milvus 等专用向量数据库也不迟。

【本站文章皆为原创,未经允许不得转载】:汤不热吧 » 如何利用 PostgreSQL pgvector 扩展实现高效的向量相似度搜索
分享到: 更多 (0)