使用 pgvector 存储和查询嵌入
Tip
有关更多详细信息,请参阅 “文本和图像 ”选项卡!
矢量嵌入将文本、图像和其他内容转换为捕获语义含义的数字表示形式。 Azure Database for PostgreSQL 支持通过 pgvector 扩展存储和查询这些嵌入内容,从而允许向现有 PostgreSQL 数据库添加矢量搜索功能,而无需管理单独的矢量存储。
本单元介绍如何启用 pgvector 扩展、为矢量存储设计架构、插入和更新嵌入以及执行基本相似性查询。 这些基础作构成了在 AI 应用程序中构建语义搜索和检索功能的基础。
启用 pgvector 扩展
pgvector 扩展将矢量数据类型和相似性搜索运算符添加到 PostgreSQL。 必须先在数据库中启用扩展,然后才能存储嵌入内容。 Azure Database for PostgreSQL 将 pgvector 作为受支持的扩展之一,使其可用,而无需进行额外的安装。
若要启用 pgvector,请连接到数据库并运行 CREATE EXTENSION 命令。 需要适当的权限才能创建扩展,通常这些权限会授予服务器管理员或具有azure_pg_admin角色的用户。
CREATE EXTENSION IF NOT EXISTS vector;
启用扩展后,可以通过查询已安装的扩展来验证它是否可用:
SELECT * FROM pg_extension WHERE extname = 'vector';
pgvector 扩展引入了 vector 数据类型,该数据类型将嵌入存储为单精度浮点数数组。 每个向量都具有在创建列时指定的固定维度数。 该扩展还提供用于计算矢量和索引类型之间的距离的运算符,以便进行快速相似性搜索。
为矢量存储设计架构
矢量存储的有效架构设计将嵌入与应用程序筛选和显示所需的元数据相结合。 定义向量列时,可以使用语法指定维度 vector(n) 数,其中 n 必须与嵌入模型的输出维度匹配。
常见的嵌入维度因模型而异。 句子转换器模型通常生成 384 维向量。 OpenAI 的文本嵌入-ada-002 模型输出 1,536 个维度,而文本嵌入-3 大型可以生成多达 3,072 个维度。 使用错误的维度计数会导致插入错误,因此请在创建表之前验证模型的输出维度。
以下示例创建一个表,该表存储具有嵌入内容以及可用于筛选和显示的元数据的法律文档:
CREATE TABLE documents (
id SERIAL PRIMARY KEY,
title TEXT NOT NULL,
content TEXT,
category TEXT,
practice_area TEXT,
created_at TIMESTAMPTZ DEFAULT NOW(),
updated_at TIMESTAMPTZ DEFAULT NOW(),
embedding vector(1536)
);
此架构将文档嵌入到与其元数据相同的行中。 此方法简化了查询,因为不需要联接来检索类似的文档及其详细信息。 对于大型内容字段,请考虑将全文存储在单独的表中,只保留主表中的摘要或标题,以减少在相似性搜索期间传输的数据。
在设计多个嵌入模型或嵌入不同的内容类型(如标题与完整内容)时,可以添加多个矢量列:
CREATE TABLE documents (
id SERIAL PRIMARY KEY,
title TEXT NOT NULL,
content TEXT,
title_embedding vector(384),
content_embedding vector(1536)
);
插入和更新嵌入
创建架构后,可以使用标准 SQL INSERT 语句插入嵌入内容。 矢量以数组格式表示为字符串文本,并转换为 vector 类型。 应用程序代码使用嵌入 API(如 Azure OpenAI)生成嵌入,并将其作为参数传递给数据库。
INSERT INTO documents (title, content, category, practice_area, embedding)
VALUES (
'Corporate Merger Agreement Template',
'This agreement outlines the terms and conditions for the merger of...',
'contracts',
'corporate',
'[0.0123, -0.0456, 0.0789, -0.0321, ...]'::vector
);
对于加载大型数据集时批量插入,请使用多行 INSERT 语句或 COPY 命令来提高性能:
INSERT INTO documents (title, content, category, embedding)
VALUES
('Document 1', 'Content...', 'legal', '[...]'::vector),
('Document 2', 'Content...', 'legal', '[...]'::vector),
('Document 3', 'Content...', 'legal', '[...]'::vector);
文档内容更改时,更新嵌入以反映新的语义含义:
UPDATE documents
SET content = 'Updated document content...',
embedding = '[0.0234, -0.0567, ...]'::vector,
updated_at = NOW()
WHERE id = 42;
对于频繁更新的应用程序,建议在非高峰时段批量处理嵌入生成,而不是在内容更改时同步更新嵌入。 此方法可减少内容更新的延迟,并合并对嵌入 API 的调用。
具有距离运算符的查询向量
pgvector 扩展提供三个距离运算符,用于测量矢量之间的相似性。 每个运算符计算不同类型的距离,并选择正确的距离取决于嵌入模型和用例。
L2 距离(Euclidean 距离) 测量嵌入空间中两个向量之间的直线距离。 将 <-> 运算符用于 L2 距离。 较小的值表示更相似的向量。 当矢量数量级具有意义时,此指标效果良好。
SELECT id, title, embedding <-> '[0.0123, -0.0456, ...]'::vector AS distance
FROM documents
ORDER BY distance
LIMIT 10;
余弦距离 测量两个向量之间的角度,忽略其数量级。 将 <=> 运算符用于余弦距离。 值范围从 0(相同的方向)到 2(相反的方向)。 余弦距离是文本嵌入的最常见选择,因为它侧重于含义的方向,而不是矢量的长度。
SELECT id, title, embedding <=> '[0.0123, -0.0456, ...]'::vector AS distance
FROM documents
ORDER BY distance
LIMIT 10;
负内积 计算两个向量的点积,并取其负值。 使用 <#> 运算符。 此指标对最大内积搜索有用,较大的点积表示向量更相似。 取负值将其转换为距离,较小值更好,与其他运算符行为一致。
SELECT id, title, embedding <#> '[0.0123, -0.0456, ...]'::vector AS distance
FROM documents
ORDER BY distance
LIMIT 10;
大多数嵌入模型(包括 OpenAI 的嵌入)都针对余弦相似性进行优化。 检查嵌入模型的文档,确认建议的距离指标。
矢量数据类型和精度
pgvector 扩展提供三种用于存储矢量的数据类型,每个数据类型具有不同的存储和性能特征。
矢量类型将元素存储为单精度(32 位)浮点数。 这是大多数用例的标准类型,提供良好的精度和存储效率平衡。 1536 维矢量使用大约 6 KB 的存储。
halfvec 类型将元素存储为半精度(16 位)浮点数。 与vector相比,此类型将存储减少一半,同时保持足够的精度以支持大多数相似性搜索任务。 存储问题时使用 halfvec ,并且你已验证降低的精度不会显著影响搜索质量。
CREATE TABLE documents_compact (
id SERIAL PRIMARY KEY,
title TEXT NOT NULL,
embedding halfvec(1536)
);
稀疏类型存储稀疏向量,其中大多数元素为零。 它只存储非零值及其位置,而不是存储所有维度。 此类型适用于生成稀疏嵌入的模型,例如某些文档表示形式。 创建列时指定最大维数。
CREATE TABLE sparse_documents (
id SERIAL PRIMARY KEY,
title TEXT NOT NULL,
embedding sparsevec(10000)
);
注释
列上的 sparsevec HNSW 索引最多支持 1,000 个非零元素。 如果稀疏向量超出此限制,请考虑减少维度或替代索引策略。
对于使用 OpenAI 或句子转换器等模型中密集嵌入的大多数 AI 应用程序,请使用标准 vector 类型。 仅在基准测试确认半精度为特定用例提供可接受的搜索质量之后才考虑 halfvec 。