-- ============================================================================ -- Phase V2-Q: pgvector 활성화 + knowledge 시맨틱 검색 -- embedding 컬럼 + cosine 유사도 검색 RPC -- ============================================================================ CREATE EXTENSION IF NOT EXISTS vector; -- 기존 knowledge_chunks에 embedding 컬럼 추가 (1536 차원 — OpenAI text-embedding-3-small) ALTER TABLE public.knowledge_chunks ADD COLUMN embedding vector(1536); -- IVFFlat 인덱스 (빠른 근사 최근접) -- 데이터 삽입 후 `REINDEX TABLE knowledge_chunks;` 권장 CREATE INDEX idx_knowledge_chunks_embedding ON public.knowledge_chunks USING ivfflat (embedding vector_cosine_ops) WITH (lists = 100); -- ============================================================================ -- match_knowledge_chunks: 쿼리 임베딩과 가장 유사한 청크 반환 -- ============================================================================ CREATE OR REPLACE FUNCTION public.match_knowledge_chunks( query_embedding vector(1536), match_count integer DEFAULT 5, similarity_threshold double precision DEFAULT 0.5 ) RETURNS TABLE ( id uuid, document_id uuid, chunk_index integer, content text, similarity double precision ) LANGUAGE plpgsql STABLE AS $$ BEGIN RETURN QUERY SELECT kc.id, kc.document_id, kc.chunk_index, kc.content, (1 - (kc.embedding <=> query_embedding))::double precision AS similarity FROM public.knowledge_chunks kc INNER JOIN public.knowledge_documents kd ON kd.id = kc.document_id WHERE kc.embedding IS NOT NULL AND ( kd.user_id = auth.uid() OR ( kd.team_id IS NOT NULL AND kd.team_id IN ( SELECT team_id FROM public.team_members WHERE user_id = auth.uid() ) ) ) AND (1 - (kc.embedding <=> query_embedding)) > similarity_threshold ORDER BY kc.embedding <=> query_embedding LIMIT match_count; END; $$; GRANT EXECUTE ON FUNCTION public.match_knowledge_chunks TO authenticated;