diff --git a/backend-lehrer/vocabulary_db.py b/backend-lehrer/vocabulary_db.py index 0150640..82b15cc 100644 --- a/backend-lehrer/vocabulary_db.py +++ b/backend-lehrer/vocabulary_db.py @@ -75,14 +75,16 @@ async def init_vocabulary_tables(): ON vocabulary_words (difficulty); CREATE INDEX IF NOT EXISTS idx_vocab_tags ON vocabulary_words USING GIN (tags); - CREATE INDEX IF NOT EXISTS idx_vocab_english_trgm - ON vocabulary_words USING GIN (english gin_trgm_ops); """) - # Enable trigram extension for fuzzy search (may already exist) + # Enable trigram extension for fuzzy search (optional) try: await conn.execute("CREATE EXTENSION IF NOT EXISTS pg_trgm;") + await conn.execute(""" + CREATE INDEX IF NOT EXISTS idx_vocab_english_trgm + ON vocabulary_words USING GIN (english gin_trgm_ops); + """) except Exception: - logger.info("pg_trgm extension already exists or cannot be created") + logger.info("pg_trgm not available — trigram search disabled, using LIKE fallback") logger.info("vocabulary_words table initialized") @@ -140,19 +142,31 @@ def _row_to_word(row) -> VocabularyWord: async def search_words( query: str, lang: str = "en", limit: int = 20, offset: int = 0, ) -> List[VocabularyWord]: - """Full-text search for words.""" + """Full-text search for words. Uses trigram similarity if available, else ILIKE.""" pool = await get_pool() col = "english" if lang == "en" else "german" async with pool.acquire() as conn: - rows = await conn.fetch( - f""" - SELECT * FROM vocabulary_words - WHERE lower({col}) LIKE $1 OR {col} % $2 - ORDER BY similarity({col}, $2) DESC, lower({col}) - LIMIT $3 OFFSET $4 - """, - f"%{query.lower()}%", query, limit, offset, - ) + # Try trigram search first, fall back to ILIKE + try: + rows = await conn.fetch( + f""" + SELECT * FROM vocabulary_words + WHERE lower({col}) LIKE $1 OR {col} % $2 + ORDER BY similarity({col}, $2) DESC, lower({col}) + LIMIT $3 OFFSET $4 + """, + f"%{query.lower()}%", query, limit, offset, + ) + except Exception: + rows = await conn.fetch( + f""" + SELECT * FROM vocabulary_words + WHERE lower({col}) LIKE $1 + ORDER BY lower({col}) + LIMIT $2 OFFSET $3 + """, + f"%{query.lower()}%", limit, offset, + ) return [_row_to_word(r) for r in rows]