August 14, 2025
код для supa
-- ===========================
-- 1) Расширения
-- ===========================
create extension if not exists vector;
create extension if not exists pg_trgm;
create extension if not exists pgcrypto;
-- ===========================
-- 2) Таблица документов
-- ===========================
create table if not exists public.documents (
id uuid primary key default gen_random_uuid(),
content text not null,
embedding vector(1536) not null,
metadata jsonb not null default '{}'::jsonb,
created_at timestamptz not null default now()
);
-- ===========================
-- 3) Индексы
-- (без CONCURRENTLY — Supabase выполняет скрипт в транзакции)
-- ===========================
create index if not exists documents_embedding_ivfflat
on public.documents using ivfflat (embedding vector_cosine_ops) with (lists = 100);
create index if not exists documents_content_trgm
on public.documents using gin (content gin_trgm_ops);
create index if not exists documents_metadata_gin
on public.documents using gin (metadata);
analyze public.documents;
-- Опционально: сколько "корзин" просматривать при ivfflat
-- (можно варьировать 1..lists; больше = медленнее, но точнее)
-- set ivfflat.probes = 10;
-- ===========================
-- 4) Функции поиска (с уникальными именами, чтобы не конфликтовать)
-- ===========================
-- 4.1 Векторный поиск (cosine)
create or replace function public.search_documents_v1(
query_embedding vector(1536),
match_count int default 10,
min_content_length int default 1
)
returns table (
id uuid,
content text,
metadata jsonb,
similarity float
)
language sql
stable
parallel safe
as $
select d.id,
d.content,
d.metadata,
1 - (d.embedding <=> query_embedding) as similarity
from public.documents d
where length(d.content) >= min_content_length
order by d.embedding <=> query_embedding
limit match_count
$;
-- 4.2 Гибридный поиск (лексика + вектор)
create or replace function public.search_documents_hybrid_v1(
query_text text,
query_embedding vector(1536),
match_count int default 10
)
returns table (
id uuid,
content text,
metadata jsonb,
similarity float
)
language sql
stable
parallel safe
as $
select d.id,
d.content,
d.metadata,
1 - (d.embedding <=> query_embedding) as similarity
from public.documents d
where
-- триграммы
d.content ilike '%' || query_text || '%'
-- и/или полнотекст (русский словарь можно заменить на 'simple', если надо)
or to_tsvector('russian', d.content) @@ plainto_tsquery('russian', query_text)
order by d.embedding <=> query_embedding
limit match_count
$;
-- ===========================
-- Готово.
-- Вставлять данные: INSERT INTO public.documents(content, metadata, embedding) VALUES (...)
-- И вызывать поиск:
-- select * from public.search_documents_v1($1::vector(1536), 10);
-- select * from public.search_documents_hybrid_v1('дурак', $2::vector(1536), 10);
-- ===========================