我正在努力在我的 Supabase 数据库中设置矢量存储,并且我需要为我创建的每个新表执行一个脚本。该脚本启用 pgvector 扩展,创建一个表,并定义一个函数来根据向量相似性搜索文档。
这是我需要执行的脚本:
-- Check if the extension exists
create extension if not exists vector;
-- Drop the function if it exists
drop function if exists match_documents(vector(1024), int, jsonb);
-- Create a table to store your documents
create table documents (
id bigint primary key generated always as identity,
content text, -- corresponds to Document.pageContent
metadata jsonb, -- corresponds to Document.metadata
embedding vector(1024) -- 1024 works for OpenAI embeddings, change if needed
);
-- Create a function to search for documents
create function match_documents (
query_embedding vector(1024),
match_count int default null,
filter jsonb default '{}'
) returns table (
id bigint,
content text,
metadata jsonb,
similarity float
) language plpgsql as $$
#variable_conflict use_column
begin
return query
select
id,
content,
metadata,
1 - (documents.embedding <=> query_embedding) as similarity
from documents
where metadata @> filter
order by documents.embedding <=> query_embedding
limit match_count;
end;
$$;
问题是这个脚本总是创建一个名为文档的表。我想创建一个函数,将表名称作为输入并执行脚本,从而允许我动态创建具有不同名称的表。该函数将使用我的 Supabase Python SDK 中的远程 RPC 调用来调用。
这是我为实现此目的而编写的函数:
create or replace function setup_vector_store(table_name text)
returns void
language plpgsql
as $$
begin
-- Enable the pgvector extension
execute 'create extension if not exists vector';
-- Drop the function if it exists
execute 'drop function if exists match_documents(vector(1024), int, jsonb)';
-- Create the table
execute format('
create table %I (
id bigint primary key generated always as identity,
content text,
metadata jsonb,
embedding vector(1024)
)', table_name);
-- Create the search function
execute format('
create function match_documents (
query_embedding vector(1024),
match_count int default null,
filter jsonb default ''{}''
) returns table (
id bigint,
content text,
metadata jsonb,
similarity float
) language plpgsql as $$
begin
return query
select
id,
content,
metadata,
1 - (''%I''.embedding <=> query_embedding) as similarity
from %I
where metadata @> filter
order by ''%I''.embedding <=> query_embedding
limit match_count;
end;
$$;', table_name, table_name, table_name);
end;
$$;
但是,当我运行这个函数时,遇到以下错误:
ERROR: 42601: syntax error at or near "#"
LINE 32: #variable_conflict use_column
^
我尝试编写这样一个函数,但在创建时遇到了问题。另外,如果还有其他方法可以动态创建这些表,请建议!
在第二个示例中,打开函数体的
$$
与还在动态 SQL $$
调用中打开另一个函数定义的 execute format(
匹配,留下孤立/错位的 #variable_conflict use_column
,我猜您之前有过那里,现在由于引号不匹配,它因其他一些令人困惑的错误而发生了变化。
用命名的美元引号替换它们:例如,外部的用
$f1$
,内部的用$f2$
:create or replace function setup_vector_store(table_name text)
returns void language plpgsql as $f1$
begin
execute format('
create table %I (
id bigint primary key generated always as identity,
content text,
metadata jsonb,
embedding varchar(1024)
)', table_name);
execute 'drop function if exists match_documents(varchar(1024), int, jsonb)';
execute format($dynsql$
create function match_documents (
query_embedding varchar(1024),
match_count int default null,
filter jsonb default ''{}''
) returns tsetof %1$I language plpgsql as $f2$
begin
return query
select
id,
content,
metadata,
(1 - length(%1$I.embedding)-length(query_embedding))::float as similarity
from %1$I
where metadata @> filter
order by length(%1$I.embedding)-length(query_embedding)
limit match_count;
end; $f2$;
$dynsql$, table_name);
end; $f1$;
请注意,如果您使用
%I
的位置表示法,则不必在 动态 SQL 调用中重复
format()
占位符。您可以多次重复使用 %1$I
,这意味着您需要 1st 参数作为 I 标识符。
我之前在这里评论过,
#
的事情需要在begin
之前换行,结果证明这是错误的。