feat: migrate semantic search to pgvector + full-text search
All checks were successful
Deploy to Production / Build and Deploy (push) Successful in 2m12s

Replace JSON-string embeddings with native pgvector(1536) storage and
add PostgreSQL full-text search (tsvector/GIN) with Reciprocal Rank Fusion
for hybrid keyword + semantic ranking.

Changes:
- NoteEmbedding.embedding: String → vector(1536) via pgvector
- NoteEmbedding: added updatedAt for reindex tracking
- Note: added tsv (tsvector) with auto-update trigger for FTS
- semantic-search.service: hybrid FTS + vector search with RRF fusion
- embedding.service: toVectorString() for pgvector SQL literals
- Removed JS-side cosine similarity loops (now DB-side via <=>)
- Added HNSW index on NoteEmbedding.embedding (cosine distance)
- Added GIN index on Note.tsv for FTS queries

Schema migration in: prisma/migrations/20260512120000_pgvector_and_fts_search/

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
Antigravity
2026-05-12 07:03:56 +00:00
parent 92c3a6f307
commit 03e6a62b80
43 changed files with 4024 additions and 786 deletions

View File

@@ -259,7 +259,6 @@ export function HomeClient({ initialNotes, initialSettings }: HomeClientProps) {
const labelFilter = searchParams.get('labels')?.split(',').filter(Boolean) || []
const colorFilter = searchParams.get('color')
const notebook = searchParams.get('notebook')
const semanticMode = searchParams.get('semantic') === 'true'
const isBackgroundRefresh = refreshKey > prevRefreshKey.current
prevRefreshKey.current = refreshKey
@@ -271,7 +270,7 @@ export function HomeClient({ initialNotes, initialSettings }: HomeClientProps) {
setIsLoading(true)
}
let allNotes = search
? await searchNotes(search, semanticMode, notebook || undefined)
? await searchNotes(search, true, notebook || undefined)
: await getAllNotes(false, notebook || undefined)
const sharedOnly = searchParams.get('shared') === '1'