feat(#65): implement full-text search with tsvector and GIN index
Add PostgreSQL full-text search infrastructure for knowledge entries: - Add search_vector tsvector column to knowledge_entries table - Create GIN index for fast full-text search performance - Implement automatic trigger to maintain search_vector on insert/update - Weight fields: title (A), summary (B), content (C) - Update SearchService to use precomputed search_vector - Add comprehensive integration tests for FTS functionality Tests: - 8/8 new integration tests passing - 205/225 knowledge module tests passing - All quality gates pass (typecheck, lint) Refs #65 Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,36 @@
|
||||
-- Add tsvector column for full-text search on knowledge_entries
|
||||
-- Weighted fields: title (A), summary (B), content (C)
|
||||
|
||||
-- Step 1: Add the search_vector column
|
||||
ALTER TABLE "knowledge_entries"
|
||||
ADD COLUMN "search_vector" tsvector;
|
||||
|
||||
-- Step 2: Create GIN index for fast full-text search
|
||||
CREATE INDEX "knowledge_entries_search_vector_idx"
|
||||
ON "knowledge_entries"
|
||||
USING gin("search_vector");
|
||||
|
||||
-- Step 3: Create function to update search_vector
|
||||
CREATE OR REPLACE FUNCTION knowledge_entries_search_vector_update()
|
||||
RETURNS trigger AS $$
|
||||
BEGIN
|
||||
NEW.search_vector :=
|
||||
setweight(to_tsvector('english', COALESCE(NEW.title, '')), 'A') ||
|
||||
setweight(to_tsvector('english', COALESCE(NEW.summary, '')), 'B') ||
|
||||
setweight(to_tsvector('english', COALESCE(NEW.content, '')), 'C');
|
||||
RETURN NEW;
|
||||
END
|
||||
$$ LANGUAGE plpgsql;
|
||||
|
||||
-- Step 4: Create trigger to automatically update search_vector on insert/update
|
||||
CREATE TRIGGER knowledge_entries_search_vector_trigger
|
||||
BEFORE INSERT OR UPDATE ON "knowledge_entries"
|
||||
FOR EACH ROW
|
||||
EXECUTE FUNCTION knowledge_entries_search_vector_update();
|
||||
|
||||
-- Step 5: Populate search_vector for existing entries
|
||||
UPDATE "knowledge_entries"
|
||||
SET search_vector =
|
||||
setweight(to_tsvector('english', COALESCE(title, '')), 'A') ||
|
||||
setweight(to_tsvector('english', COALESCE(summary, '')), 'B') ||
|
||||
setweight(to_tsvector('english', COALESCE(content, '')), 'C');
|
||||
@@ -798,6 +798,9 @@ model KnowledgeEntry {
|
||||
contentHtml String? @map("content_html") @db.Text
|
||||
summary String?
|
||||
|
||||
// Full-text search vector (automatically maintained by trigger)
|
||||
searchVector Unsupported("tsvector")? @map("search_vector")
|
||||
|
||||
// Status
|
||||
status EntryStatus @default(DRAFT)
|
||||
visibility Visibility @default(PRIVATE)
|
||||
@@ -820,6 +823,7 @@ model KnowledgeEntry {
|
||||
@@index([workspaceId, updatedAt])
|
||||
@@index([createdBy])
|
||||
@@index([updatedBy])
|
||||
// Note: GIN index on searchVector created via migration (not supported in Prisma schema)
|
||||
@@map("knowledge_entries")
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user