Supabase Vector:基于 Postgres 与 pgvector 的向量存储、索引与相似度检索实践
2026/9/7 15:33:11 网站建设 项目流程

Supabase Vector:基于 Postgres 与 pgvector 的向量存储、索引与相似度检索实践

【免费下载链接】supabaseThe Postgres development platform. Supabase gives you a dedicated Postgres database to build your web, mobile, and AI applications.项目地址: https://gitcode.com/GitHub_Trending/supa/supabase

Supabase Vector 是把向量嵌入(vector embeddings)直接存储在与业务事务数据同一个 Postgres 数据库中的 AI 向量检索工具包,底层由开源扩展 pgvector 驱动。本篇围绕仓库中的产品说明 vector.md 展开,结合官方文档(apps/docs/content/guides/ai/目录)与examples/ai/下的可运行示例,完整讲解从生成嵌入、建表建索引到带元数据过滤的混合 SQL 查询的全流程,读完你可以直接在 Supabase 项目中落地语义搜索、RAG 与图像相似度检测等场景。

什么是 Supabase Vector

Supabase Vector 的定位可以概括为一句话:用你已经拥有的数据库做向量数据库。它让你无需引入独立的向量数据库,就能在生产级 Postgres 中获得向量存储、索引与近似最近邻(ANN)检索能力。产品说明文档给出了它的核心特性,逐条对应仓库中可验证的实现如下:

特性说明仓库中的对应证据
pgvector 集成直接在 Postgres 中存储、索引和查询向量嵌入pgvector 扩展文档 介绍了启用vector扩展及建表用法
数据共置(Co-located)向量嵌入与关系型数据同库存放,可用标准 SQL 做 JOINedge-functions 示例迁移 与业务表同 schema,并启用了 RLS
多种索引类型IVFFlat 与 HNSW 两种 ANN 索引HNSW 索引文档、IVFFlat 索引文档
多种距离度量余弦距离、L2(欧氏)距离、最大内积Vector columns 文档 给出三个距离算子与对应算子类
元数据过滤可按任意列或 JSONB 元数据过滤相似度查询语义搜索文档 提供按元数据过滤的完整 JS 示例
Python 客户端(vecs)管理 collection、upsert 向量与查询的专用 Python 库vecs 客户端文档
LLM 集成支持 OpenAI、Hugging Face、Amazon SageMaker、LangChain 等AI 指南 的 Integrations 章节及examples/ai/下的 Bedrock 图像搜索示例、LlamaIndex 示例
Edge Functions 生成嵌入在 Edge Functions 中直接用开源模型生成嵌入generate-embedding 函数 使用Supabase.ai.Session('gte-small')
可自托管整套技术栈可运行在自己的基础设施上仓库根目录的 docker/docker-compose.yml 即自托管部署入口
SOC2 Type 2 合规企业级安全合规产品说明声明

常见使用场景

产品文档列出的典型场景,本质上都归结为"用距离度量代替关键字匹配":

  • 语义搜索:对文档、知识库或工单按含义而非关键字检索,参见 语义搜索指南;
  • RAG(检索增强生成):为大模型应用建立可检索的外部知识层,官方文档还覆盖了带权限控制的 RAG with permissions;
  • 图像相似度检测:将图片编码为向量后按余弦距离检索,仓库内提供 image_search 示例 与 face_similarity 笔记本;
  • 推荐引擎:基于用户/物品向量找最近邻;
  • 自动打标签与内容分类
  • 带长期记忆的 ChatGPT 插件:building-chatgpt-plugins 文档 讲解把 Supabase 作为插件检索存储。

工作原理:五步流水线

产品文档将工作机制归纳为五步,下面逐步展开,并给出仓库中真实可复现的 SQL 与代码。

第一步:用任意模型生成嵌入

嵌入模型不限于某一个供应商,可选 OpenAI、Hugging Face、Cohere 等。仓库 edge-functions 示例 展示的是"开源模型 + Edge Functions"路线:在 Deno 运行时中直接实例化模型会话:

// examples/ai/edge-functions/supabase/functions/generate-embedding/index.ts(节选) const model = new Supabase.ai.Session('gte-small') // 生成嵌入:mean pooling + 归一化到单位长度 const embedding = await model.run(content, { mean_pool: true, normalize: true, })

这里有两个关键参数:mean_pool: true对 token 向量做平均池化得到句向量;normalize: true把向量归一化到长度 1——这一步直接决定了后续可以用更便宜的内积运算替代余弦距离(见第四步)。

第二步:把嵌入存进带vector列的 Postgres 表

先在数据库启用vector扩展(扩展名即vector,而不是pgvector),然后声明带维度的向量列。仓库中真实的迁移脚本如下:

-- examples/ai/edge-functions/supabase/migrations/20240408072601_embeddings.sql create extension if not exists pg_net with schema extensions; create extension if not exists vector with schema extensions; create table embeddings ( id bigint primary key generated always as identity, content text not null, embedding vector (384) ); alter table embeddings enable row level security;

vector(384)中的 384 必须与你所用嵌入模型的输出维度一致:上例中的开源模型gte-small输出 384 维。Vector columns 文档 补充了一条经验:总体而言维度更少的嵌入表现更好,因此选型时可在精度与维度之间权衡。embedding只是普通列名,可以随意命名;迁移脚本同时开启了 RLS,说明向量表与业务表一样受 Supabase 的行级安全策略保护。

第三步:创建 HNSW 或 IVFFlat 索引加速检索

同一迁移脚本在表建好后立即创建了 HNSW 索引:

-- 20240408072601_embeddings.sql 最后一行 create index on embeddings using hnsw (embedding vector_ip_ops);

索引类型和算子类必须与查询使用的距离算子匹配。pgvector 提供三个距离算子,与算子类的对应关系(摘自 vector-columns.mdx):

算子含义算子类
<->欧氏(L2)距离vector_l2_ops
<#>负内积vector_ip_ops
<=>余弦距离vector_cosine_ops

因此若查询走内积,就应建vector_ip_ops的 HNSW 索引,否则索引无法被该算子使用。

第四步:用距离算子查询

相似度检索是最常见用法,直接按距离排序即可:

-- 余弦距离示例(来自 pgvector 扩展文档的查询写法) select * from embeddings order by embedding <=> '[...]' limit 5;

若要通过 Supabase 客户端(如supabase-js)调用,由于客户端经由 PostgREST 访问 Postgres,而 PostgREST 不支持 pgvector 的相似度算子,需要把查询包在 Postgres 函数中再用rpc()调用。仓库中的 query_embeddings 函数 是完整范例:

-- examples/ai/edge-functions/supabase/migrations/20240410031515_vector-search.sql create or replace function query_embeddings(embedding vector(384), match_threshold float) returns setof embeddings language plpgsql as $$ begin return query select * from embeddings -- 内积符号相反,因此对 match_threshold 取负 where embeddings.embedding <#> embedding < -match_threshold -- 嵌入已归一化到长度 1,余弦相似度与内积结果等价, -- 而内积计算更快,所以这里选用 <#> order by embeddings.embedding <#> embedding; end; $$;

这段源码印证了文档中"归一化向量下内积最快"的结论:因为嵌入生成时就执行了normalize: true<#><=>的排序结果一致,选内积只是为了省一次范数计算。match_threshold参数则保证只返回相似度超过最低阈值的行,避免返回主观上不相关的内容——阈值取值需要按业务自测确定。

官方文档还给出了另一种等价的 RPC 写法(vector-columns.mdx),带match_count参数并在返回列中显式计算similarity

create or replace function match_documents ( query_embedding extensions.vector(384), match_threshold float, match_count int ) returns table (id bigint, title text, body text, similarity float) language sql stable as $$ 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; $$;

客户端调用只需:

const { data: documents } = await supabaseClient.rpc('match_documents', { query_embedding: embedding, // 查询文本生成的嵌入 match_threshold: 0.78, // 按数据特点调整 match_count: 10, // 返回条数 })

两个要点(均来自文档中的注意事项):一、order by必须直接按距离函数排序(如上例),而不是按算出来的similarity列排序,否则可能绕过索引导致性能劣化;二、参与距离计算的嵌入必须来自同一个嵌入模型,跨模型比较没有意义。

第五步:与标准 SQL 组合做混合查询

向量列与普通列同表,意味着可以任意叠加JOINWHEREGROUP BY。仓库中的 search 函数 展示了完整的线上形态:先为搜索词生成嵌入,再调 RPC 取回 Top-N 并链式.select('content').limit(3)

const { data: result, error } = await ctx.supabaseAdmin .rpc('query_embeddings', { embedding: JSON.stringify(embedding), match_threshold: 0.8, }) .select('content') .limit(3)

配合元数据过滤时,在函数上多加一个参数和where子句即可,完整示例见 语义搜索文档的"Filtering vector search by metadata"一节。另有一个实现细节值得注意:ANN 索引在带过滤条件时可能返回少于LIMIT的行(索引先按距离取候选、过滤后数量不足),官方文档在 pgvector 扩展页 中给出了规避方案——使用 pgvector 的 iterative index scans 继续扫描索引直到凑足结果,HNSW 的具体机制见下文。

HNSW 索引:原理、维度上限与调优

HNSW 是产品文档标注为"recommended"的默认索引类型。HNSW 索引文档 将其拆解为两个概念:

**分层(Hierarchical)**借鉴跳表思想:底层是连接所有节点的稠密图,每往上一层按固定概率抽稀,形成越来越稀疏的长距离连接。搜索从顶层开始,找不到目标就下沉到下一层,逐层收敛。

可导航小世界(Navigable Small World):每个向量是图上的一个节点,除连接近邻外还带少量长程连接,使几乎任意节点都能在数跳内到达;贪心搜索因此能以接近对数的复杂度导航图结构。

维度上限。产品页给出的规格是"Max dimensions: 2,000 (HNSW), 16,000+ (flat)"。官方文档的更精确口径是:pgvector 0.7.0 及以上版本中,HNSW 索引支持vector类型最多 2,000 维、halfvec最多 4,000 维、bit最多 64,000 维;可用SELECT * FROM pg_extension WHERE extname = 'vector';查看当前版本。超出 2,000 维的场景可用halfvec转型建索引,例如 3,072 维的嵌入:

CREATE TABLE documents ( id bigint GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY, content text, embedding vector(3072) ); CREATE INDEX ON documents USING hnsw ((embedding::halfvec(3072)) halfvec_cosine_ops);

建索引时机。与 IVFFlat 不同,HNSW 基于图结构,建表后即可立即构建,新数据插入时索引自动填充并保持结构最优,不需要等数据量积累到位。

过滤与 iterative index scans。给向量查询加where不会绕过 HNSW 索引,Postgres 规划器会根据过滤选择性与表规模在索引扫描和顺序扫描之间做选择;代价是过滤条件高选择性时,索引先返回的 Top-k 被大量过滤掉,最终行数可能少于LIMIT。从 pgvector 0.8.0 起,规划器支持由hnsw.iterative_scanGUC 控制的迭代索引扫描(默认off),两种启用模式为:strict_order(跨轮次保持严格距离顺序)与relaxed_order(允许轻微重排以换取更高召回)。扫描深度由hnsw.max_scan_tuples(默认 20,000)和hnsw.scan_mem_multiplier(默认 1)约束(摘自 HNSW 索引文档)。

IVFFlat 索引:lists 与 probes 的权衡

IVFFlat 索引文档 说明其原理是倒排文件索引:建索引时对向量做聚类(倒排列表 / cell clusters),查询时只与命中的邻近聚类比较,而不是全表比较。建索引 SQL 需指定lists数量,例如:

create index on items using ivfflat (column_name vector_cosine_ops) with (lists = 100);

核心权衡参数:

  • lists:越大查询越快,但召回率越差;
  • probes:每次查询探测的邻近聚类数(默认 1),越大召回越好但越慢,可按会话设置set ivfflat.probes = 10;,或按事务设置set local ivfflat.probes = 10;。当 probes 等于 lists 时退化为精确搜索,规划器将不再使用该索引;
  • 建索引时机:官方建议在表已有足够数据后再建,使内部聚类基于真实数据分布;数据分布显著变化时应考虑重建索引。这也是文档推荐默认使用 HNSW 的两个理由之一(另一个是性能)。

Edge Functions 全链路:从写入 Webhook 到语义搜索

examples/ai/edge-functions/把前述五步串成了一个可在本地跑通的完整闭环(README 提供本地启动与 curl 调用说明),其数据流是:

  1. 业务表发生 INSERT/UPDATE 时,Postgres Webhook 触发 generate-embedding 函数。函数先比较contentold_record.content,内容未变则直接返回ok - no change,避免重复推理;有变化则调用gte-small模型生成嵌入,用supabaseAdmin客户端写回embeddings表。
  2. 客户端发起搜索时,search 函数 对搜索词生成嵌入,调用query_embeddingsRPC(match_threshold: 0.8)取回 Top-3 内容。
  3. 两个函数均以apikey头携带密钥调用,部署时verify_jwt = false,即绕过 JWT 校验、走服务侧密钥认证。

本地验证命令(摘自 search 函数源码注释):

# 1. supabase start # 2. supabase functions serve # 3. 发起搜索请求 curl -i --location --request POST 'http://127.0.0.1:54321/functions/v1/search' \ --header 'apikey: <SUPABASE_SECRET_KEY>' \ --header 'Content-Type: application/json' \ --data '{"search":"vehicles"}'

技术规格与生产化要点

对照产品文档的 Technical Details 逐项说明:

  • 扩展:pgvector,开源 Postgres 扩展,启用方式为create extension vector with schema extensions;(见 pgvector 文档),禁用为drop extension if exists vector;
  • 最大维度:HNSW 索引 2,000 维(vector类型)、flat 16,000+;补充上文所述halfvec(4,000 维)、bit(64,000 维)的扩展上限,以及 >2,000 维时的halfvec转型建索引方案。
  • 索引类型:HNSW(推荐默认)与 IVFFlat,选择依据见上面两节。
  • 扩缩容:向量检索与你所在 Supabase 数据库共享同一套计算扩缩容(Micro 到 16XL 的计算规格),容量规划可参考 选择计算规格文档;更大的工程化讨论见 engineering-for-scale。
  • 备份:每日自动备份 + PITR(point-in-time recovery)。
  • Python 客户端vecs提供 collection 管理、upsert 与查询的高层 API,适合以"向量集合"而非裸表方式组织的未结构化嵌入,详见 vecs-python-client 文档;结构化嵌入则建议走数据库迁移管理(参见 headless-vector-search 示例 的数据库准备部分)。
  • 模型与框架集成:仓库examples/ai/目录收录了 Amazon Bedrock 图像生成/检索(aws_bedrock_image_search)、LlamaIndex(llamaindex.ipynb)、llamafile 边端推理等示例;LangChain、Hugging Face 等集成指南见 AI 指南 的 Integrations 章节。
  • 生产检查清单:上线前的部署考量(含向量场景)见 going-to-prod 文档;查询变慢时优先考虑补 HNSW 索引,对应排查指南见 troubleshooting/increase-vector-lookup-speeds-by-applying-an-hsnw-index-ohLHUM.mdx。

小结

Supabase Vector 的价值在于消除独立向量数据库的引入成本:嵌入与事务数据同库同 schema,索引、备份、扩缩容、行级安全全部复用 Postgres 既有能力;三个距离算子、HNSW/IVFFlat 两类索引以及 RPC 封装模式,覆盖了从几十条到生产规模的知识库检索需求。建议按"迁移脚本建表建索引(20240408072601_embeddings.sql)→ RPC 函数封装查询(20240410031515_vector-search.sql)→ Edge Functions 生成与检索(examples/ai/edge-functions)"的路径在当前仓库内复现完整链路,再按需引入halfvec、iterative scans 或vecs客户端做进阶优化。

【免费下载链接】supabaseThe Postgres development platform. Supabase gives you a dedicated Postgres database to build your web, mobile, and AI applications.项目地址: https://gitcode.com/GitHub_Trending/supa/supabase

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询