向量列
Supabase 提供了多种在 Postgres 中存储和查询向量的方法。本指南中的 SQL 适用于所有编程语言的客户端。如果您是 Python 用户,在阅读完"学习"部分后,请查看您的 Python 客户端选项。
Supabase 中的向量功能通过 pgvector 实现,这是一个用于在 Postgres 中存储和查询向量的扩展。它可用于存储 嵌入向量。
使用方法
启用扩展
- 进入控制面板中的数据库页面
- 点击侧边栏中的扩展
- 搜索"vector"并启用该扩展
创建存储向量的表
启用 vector
扩展后,您将获得名为 vector
的新数据类型。向量大小(括号内数字)表示该向量存储的维度数量。
123456create table documents ( id serial primary key, title text not null, body text not null, embedding vector(384));
在上述 SQL 代码片段中,我们创建了一个 documents
表,其中包含名为 embedding
的列(注意这只是普通的 Postgres 列 - 您可以任意命名)。我们将 embedding
列设置为具有 384 维的 vector
数据类型。请根据您的嵌入模型产生的维度数修改此值。例如,如果您使用开源的 gte-small
模型生成嵌入向量,则应将该数字设为 384,因为该模型会产生 384 维向量。
通常,维度较少的嵌入向量表现最佳。参阅我们关于 pgvector 中较少维度的分析。
存储向量/嵌入
在这个示例中,我们将使用 Transformers.js 生成一个向量,然后通过 Supabase JavaScript 客户端将其存储到数据库中。
123456789101112131415161718192021import { pipeline } from '@xenova/transformers'const generateEmbedding = await pipeline('feature-extraction', 'Supabase/gte-small')const title = 'First post!'const body = 'Hello world!'// 使用 Transformers.js 生成向量const output = await generateEmbedding(body, { pooling: 'mean', normalize: true,})// 提取嵌入输出const embedding = Array.from(output.data)// 将向量存储到 Postgresconst { data, error } = await supabase.from('documents').insert({ title, body, embedding,})
本示例使用了 JavaScript 版的 Supabase 客户端,但您可以修改它以适配任何支持的编程语言库。
查询向量/嵌入
相似性搜索是向量最常见的用例。pgvector
支持3种新的距离计算运算符:
运算符 | 描述 |
---|---|
<-> | 欧几里得距离 |
<#> | 负内积 |
<=> | 余弦距离 |
选择合适的运算符取决于您的需求。如果向量已归一化,点积通常是速度最快的选择。有关嵌入工作原理及其相互关系的更多信息,请参阅什么是嵌入?。
像 supabase-js
这样的 Supabase 客户端库通过 PostgREST 连接到您的 Postgres 实例。PostgREST 目前不支持 pgvector
的相似性运算符,因此我们需要将查询封装在 Postgres 函数中,并通过 rpc()
方法调用:
1234567891011121314151617181920212223create or replace function match_documents ( query_embedding vector(384), match_threshold float, match_count int)returns table ( id bigint, title text, body text, similarity float)language sql stableas $$ select documents.id, documents.title, documents.body, 1 - (documents.embedding <=> query_embedding) as similarity from documents where 1 - (documents.embedding <=> query_embedding) > match_threshold order by (documents.embedding <=> query_embedding) asc limit match_count;$$;
此函数接收 query_embedding
参数,并将其与 documents
表中的所有其他嵌入进行比较。每次比较都会返回一个相似度分数。如果相似度大于 match_threshold
参数,则返回该记录。返回的行数由 match_count
参数限制。
您可以根据应用需求自由修改此方法。match_threshold
确保只返回与 query_embedding
具有最低相似度的文档。没有这个阈值,可能会返回主观上不匹配的文档。这个值因应用而异——您需要进行自己的测试来确定适合您应用的阈值。
如果对向量列建立了索引,请确保 order by
直接按距离函数排序(而不是按计算的 similarity
列排序,否则可能导致索引被忽略和性能下降)。
要从客户端库执行此函数,使用 rpc()
调用您的 Postgres 函数:
12345const { data: documents } = await supabaseClient.rpc('match_documents', { query_embedding: embedding, // 传入要比较的嵌入向量 match_threshold: 0.78, // 为您的数据选择合适的阈值 match_count: 10, // 选择匹配数量})
在这个例子中,embedding
是您希望与预生成嵌入文档表进行比较的另一个嵌入向量。例如,如果您正在构建搜索引擎,每次用户提交查询时,您会先为搜索查询本身生成嵌入,然后将其传入上述 rpc()
函数进行匹配。
计算距离时,务必使用来自同一嵌入模型生成的嵌入。比较来自两个不同模型的嵌入不会产生有意义的结果。
向量和嵌入的用途远不止搜索。了解更多关于嵌入的信息,请参阅什么是嵌入?。
索引
当您的向量表开始增长时,您可能会希望添加索引以加速查询。请参阅向量索引了解向量索引的工作原理及创建方法。