You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
While evaluating whether we can retire the OpenAI-driven semantic layer, we catalogued the current search stack and identified places where plain PostgreSQL full-text search (FTS) could cover most use cases with less complexity.
Current State
Text path already indexes name, street, city, and country on the fly via to_tsvector('english', …).
Semantic path calls OpenAI text-embedding-3-small, stores vectors in pgvector, and uses cosine similarity + category fallbacks before re-querying Postgres.
Autocomplete relies exclusively on the text path; embeddings are only precomputed in the background.
SIMILARITY_THRESHOLD is intentionally low (0.3) to catch looser matches, which increases recall but also noise and cost.
Pain Points
External dependency, latency, and cost from embedding generation + caching plumbing.
Persist a generated tsvector column on locations with a GIN index instead of rebuilding vectors per request.
Swap to_tsquery sanitisation for websearch_to_tsquery to better handle natural language and punctuation.
Add weighting + ts_rank_cd so name hits outrank address-only matches.
Maintain a lightweight synonym table or expand KEYWORD_FALLBACKS for domain-specific equivalences (espresso ↔ café, btc ↔ crypto, etc.).
Localise FTS dictionaries when we need non-English stemming instead of relying on embeddings for language coverage.
UI & UX Ideas
Surface direct category pills inside autocomplete when the query matches a known category ID, so users can jump straight to that filter.
Optionally show the category icon in text results using the existing icon select field from searchLocationsByCategories.
Recommended Experiments
FTS-only baseline: disable the semantic branch behind a flag and record coverage/latency deltas on a copy of production data.
Hybrid vs FTS A/B: run both paths for a week, log result counts, first-result relevance, and latency; feed logs into the harness from Add offline embedding regression tests #65.
Indexing impact: benchmark response times before/after adding the stored tsvector column + GIN index.
Synonym table trial: curate 20–30 high-value synonyms and compare recall against the embedding path for the same queries.
Context
While evaluating whether we can retire the OpenAI-driven semantic layer, we catalogued the current search stack and identified places where plain PostgreSQL full-text search (FTS) could cover most use cases with less complexity.
Current State
name,street,city, andcountryon the fly viato_tsvector('english', …).text-embedding-3-small, stores vectors in pgvector, and uses cosine similarity + category fallbacks before re-querying Postgres.SIMILARITY_THRESHOLDis intentionally low (0.3) to catch looser matches, which increases recall but also noise and cost.Pain Points
Simplification Opportunities
tsvectorcolumn onlocationswith a GIN index instead of rebuilding vectors per request.to_tsquerysanitisation forwebsearch_to_tsqueryto better handle natural language and punctuation.ts_rank_cdso name hits outrank address-only matches.KEYWORD_FALLBACKSfor domain-specific equivalences (espresso ↔ café, btc ↔ crypto, etc.).UI & UX Ideas
iconselect field fromsearchLocationsByCategories.Recommended Experiments
tsvectorcolumn + GIN index.Next Steps
Open Questions