pgvector 是一个开源的 PostgreSQL 扩展,它为数据库添加了向量类型和向量相似性搜索功能。它引入了 vector 数据类型和一系列操作符、函数,让你能用标准的 SQL 进行向量运算。
本文将围绕存储、查询、聚合等核心操作,通过具体示例展示 pgvector 的基础使用方法。
一、存储数据和更改
创建向量表
创建一个包含向量列的表。在定义向量列时,需要指定其维度(例如下面例子中的 3 维)。
CREATE TABLE items (
id bigserial PRIMARY KEY,
embedding vector(3)
);
向现有表中添加向量列
如果你需要为已有表添加向量列,可以使用 ALTER TABLE 命令。同时,pgvector 也支持半精度、二进制和稀疏向量。
ALTER TABLE items ADD COLUMN embedding vector(3);
插入向量数据
插入数据时,向量以字符串格式表示,如 '[1,2,3]'。
INSERT INTO items (embedding) VALUES
('[1,2,3]'),
('[4,5,6]'),
('[5,4,6]');
插入向量数据(处理冲突)
可以使用 INSERT … ON CONFLICT 来处理冲突。
INSERT INTO items (id, embedding) VALUES (1, '[1,2,3]')
ON CONFLICT (id) DO UPDATE
SET embedding = EXCLUDED.embedding;
COPY或者使用(例如)批量加载向量
COPY items (embedding) FROM STDIN WITH (FORMAT BINARY);
更新和删除向量
向量数据的更新和删除操作与普通数据无异。
UPDATE items SET embedding = '[1,2,3]' WHERE id = 1;
DELETE FROM items WHERE id = 1;
二、查询
相似度搜索是 pgvector 的核心功能。通过专用的距离操作符,你可以找到与目标向量最相似的记录。
支持的距离函数有:
<-> L2 距离(欧几里得距离)
<#>(负)内积
<=> 余弦距离
<+> L1 距离(曼哈顿距离)
<~> 汉明距离(二进制向量)
<%> Jaccard (杰卡德)距离(二进制向量)

如何选择距离函数?这取决于你的数据和应用场景:
- 场景1:找地理位置最近的点 → 用L2欧几里得
- 场景2:找内容相似的新闻 → 用余弦距离(忽略文章长度)
- 场景3:找偏好相似的用户 → 用Jaccard距离(只看共同喜好)
- 场景4:找词义相近的词 → 用负内积(考虑词频)
- 场景5:找特征相似的图像 → 用L1曼哈顿(稀疏特征)
- 场景6:找错误最少的编码 → 用汉明距离
1. <-> L2 距离排序(欧几里得距离)
L2距离 = $\sqrt{\Sigma(x_i-y_i)^2}$。例如 [1,2,3] 和 [4,5,6] 的 L2 距离 = $\sqrt{(1-4)^2 + (2-5)^2 + (3-6)^2}$ = $\sqrt{27}$ ≈ 5.196。
- 几何意义:两点之间的直线距离,最直观的空间距离。
- 适用场景:地理位置、图像像素差、聚类算法。
按欧几里得距离 (L2) 排序,使用 <-> 操作符。
获取向量的最近邻:
SELECT * FROM items
ORDER BY embedding <-> '[3,1,2]'
LIMIT 5;
获取与某一行最近的邻居:
SELECT * FROM items WHERE id != 1 ORDER BY embedding <-> (SELECT embedding FROM items WHERE id = 1) LIMIT 5;
获取特定距离内的行:
SELECT * FROM items WHERE embedding <-> '[3,1,2]' < 5;
注意:结合使用 ORDER BY 和 LIMIT 来有效使用索引。
获取距离值:
SELECT embedding <-> '[3,1,2]' AS distance FROM items;
2. <#>(负)内积排序
内积 = $\Sigma(x_i × y_i)$。例如 [1,2,3] 和 [4,5,6] 的内积 = $1×4 + 2×5 + 3×6 = 32$,其负内积 = $-32$。
- 几何意义:向量在方向上的投影长度乘积,包含长度和方向信息。
- 特点:值越小表示相似度越高(因为内积越大越相似,取负后越小越相似)。
- 适用场景:词向量相似度、矩阵分解、神经网络最后一层。
按内积距离排序,使用 <#> 操作符。注意,该操作符返回的是负的内积,因为 PostgreSQL 索引默认支持升序扫描。要获得真实的内积,需要对结果取负。
SELECT *, (embedding <#> '[3,1,2]') * -1 AS inner_product
FROM items
ORDER BY embedding <#> '[3,1,2]'
LIMIT 5;
3. <=> 余弦距离
余弦相似度 = 内积 / (|a|×|b|),余弦距离 = 1 - 余弦相似度。
- 几何意义:忽略向量长度,只关注方向夹角。
- 适用场景:文本相似度、不考虑幅度的特征比较、推荐系统。
按余弦距离排序,使用 <=> 操作符。若要获得余弦相似度(值越接近 1 表示越相似),可以使用 1 - (embedding <=> '[3,1,2]')。
SELECT *, 1 - (embedding <=> '[3,1,2]') AS cosine_similarity
FROM items
ORDER BY embedding <=> '[3,1,2]'
LIMIT 5;
计算余弦相似度:
SELECT 1 - (embedding <=> '[3,1,2]') AS cosine_similarity FROM items;
4. <+> L1 距离(曼哈顿距离)
L1距离 = $\Sigma|x_i - y_i|$。例如 [1,2,3] 和 [4,5,6] 的 L1 距离 = $|1-4| + |2-5| + |3-6| = 9$。
- 几何意义:在网格上只能沿坐标轴方向移动的距离,像城市街区距离。
- 适用场景:特征向量、稀疏数据、推荐系统。
L1 距离是所有维度差的绝对值之和,也叫曼哈顿距离或街区距离。
查询每个向量与 [3,3,3] 的 L1 距离:
SELECT
id,
embedding,
'[3,3,3]' as target,
embedding <+> '[3,3,3]' as l1_distance
FROM items
ORDER BY l1_distance;
计算两个具体向量的 L1 距离:
SELECT
(SELECT embedding FROM items WHERE id=1) <+>
(SELECT embedding FROM items WHERE id=2) as l1_distance_1_2;
5. <~> 汉明距离(二进制向量)
汉明距离 = 不同位的数量。
- 几何意义:二进制字符串需要改变多少位才能变成另一个。
- 适用场景:错误检测、编码理论、二进制特征比较。
汉明距离用于二进制向量,需要先创建二进制向量表:
-- 创建二进制向量表
CREATE TABLE binary_items (
id bigserial PRIMARY KEY,
embedding bit(3) -- 3位二进制向量
);
INSERT INTO binary_items (embedding) VALUES
(B'101'), -- item 1
(B'111'), -- item 2
(B'100'); -- item 3
-- 计算汉明距离
SELECT
id,
embedding,
B'101' as target,
embedding <~> B'101' as hamming_distance
FROM binary_items
ORDER BY hamming_distance;
-- 计算 [101] 和 [111] 的汉明距离
SELECT
B'101' <~> B'111' as hamming_distance;
6. <%> Jaccard 距离 (杰卡德距离,二进制向量,集合相似度)
Jaccard距离 = 1 - Jaccard相似度,Jaccard相似度 = 交集大小 / 并集大小。
- 几何意义:集合的差异程度,忽略共同为0的部分。
- 适用场景:集合相似度、推荐系统、标签匹配。
-- 使用相同的二进制向量表
SELECT
id,
embedding,
B'101' as target,
embedding <%> B'101' as jaccard_distance
FROM binary_items
ORDER BY jaccard_distance;
-- 计算 [101] 和 [111] 的 Jaccard 距离
SELECT
B'101' <%> B'111' as jaccard_distance;
三、其他操作
平均值
pgvector 还支持向量聚合操作,如求平均值。
平均向量:
SELECT AVG(embedding) FROM items;
向量组的平均:
SELECT id, AVG(embedding) FROM items GROUP BY id;
向量维度和范数
一些辅助函数,如获取向量维度和范数:
SELECT
embedding,
vector_dims(embedding) AS dimensions,
vector_norm(embedding) AS norm
FROM items;
掌握以上这些基础操作,你就能在 PostgreSQL 中利用 pgvector 有效地存储和检索向量数据了。从简单的距离计算到复杂的相似度搜索,pgvector 提供了一套完整的 SQL 接口,让向量运算变得像处理普通数据一样简单。