- ArticleEmbeddingRepo (new): Upsert, GetByArticleID, DeleteByArticleID, SearchByEmbedding using pgvector cosine distance (vector_embedding column) - ArticleEmbedding model: add VectorEmbedding pgvector.Vector field alongside existing JSONB Embedding (backward compatible) - ArticleService: add SemanticSearch() — generates query embedding via LLM, searches articles by cosine similarity; add GenerateEmbedding() — creates and stores article embedding from title+description+content - ArticleHandler: add SemanticSearch endpoint GET /portals/:portal_id/articles/semantic_search?query=... - bootstrap.go: inject articleEmbeddingRepo + llmProvider into ArticleService - router.go: register /articles/semantic_search route - migration 000049: add vector(1536) column to article_embeddings table, create ivfflat index, migrate existing JSONB data to vector format Verified: go build + go vet + go test all pass
26 lines
1.1 KiB
SQL
26 lines
1.1 KiB
SQL
-- 000049_add_article_embedding_vector.up.sql
|
|
-- Add pgvector vector column to article_embeddings for semantic search.
|
|
-- The original embedding JSONB column is kept for backward compatibility;
|
|
-- the new vector_column stores the same data as a native pgvector type
|
|
-- enabling the <=> (cosine distance) operator for efficient similarity search.
|
|
|
|
-- Ensure pgvector extension is available (should already be installed).
|
|
CREATE EXTENSION IF NOT EXISTS vector;
|
|
|
|
-- Add a vector(1536) column to article_embeddings
|
|
ALTER TABLE article_embeddings ADD COLUMN IF NOT EXISTS vector_embedding vector(1536);
|
|
|
|
-- Create an index for efficient cosine similarity search
|
|
CREATE INDEX IF NOT EXISTS idx_article_embeddings_vector
|
|
ON article_embeddings USING ivfflat (vector_embedding vector_cosine_ops)
|
|
WITH (lists = 100);
|
|
|
|
-- Migrate existing JSONB embeddings to the vector column
|
|
-- This parses the JSON array into a pgvector-compatible format
|
|
UPDATE article_embeddings
|
|
SET vector_embedding = (
|
|
SELECT array_agg(elem::real)::vector(1536)
|
|
FROM jsonb_array_elements_text(embedding) AS elem
|
|
)
|
|
WHERE vector_embedding IS NULL AND embedding IS NOT NULL;
|