I Assumed Users Would Search for Movie Titles. I Was Wrong.
I was checking analytics on FilmFlux one afternoon and saw something I didn't expect. Most search queries returned zero results.
Not slow searches. Not vague searches. Zero results. People were typing things into the search bar and getting an empty page back, then leaving. The bar I'd designed to be helpful was the bar pushing them out the door.
What they were typing
Curious, I started reading the queries. None of them looked like what I'd built for. I'd built a movie title search. Users were searching:
- "Mercy Johnson movies"
- "2024 romantic comedy"
- "movie about a heist gone wrong"
- "films like John Wick"
These weren't titles. They were intent. The database was structured for exact title matches; users were thinking in vibes, decades, actors, themes. SQL pattern matching returned nothing because the words they typed weren't anywhere in the title field. The content existed (every single one of those queries had matching films in the database) but the search couldn't find them.
The gap between how I stored data and how users searched for it is where the product was failing.
The fix
I architected a hybrid search system using Supabase Edge Functions. Pure semantic search fails on specific keywords. You can't embed the year 2024. Pure keyword search fails on context. I needed both, and a way to combine them so each query got the right tool.
Four layers
Semantic understanding
OpenAI embeddings to match vibe and plot. A query like "movie about a heist gone wrong" finds the right films even without title keywords.
Intent detection
Logic to parse natural language filters. Years, genres, actors, and combinations like "2024 romantic comedy" get decomposed into structured filters before search.
Fuzzy matching
pg_trgm to handle typos. "Merci Johson" still finds Mercy Johnson. Users don’t get punished for misspelling.
Recency weighting
Custom ranking to surface new hits, not obscure back-catalog titles. Recent, popular content ranks higher when relevance scores are close.
One query, four layers
Here's what “Mercy Johnson movies” looks like as it moves through the system:
- 1Intent detection parses the query, recognises "Mercy Johnson" as a person, and filters for films where she’s listed in the cast.
- 2Semantic search ranks the filtered set by how well her work matches the implied "movies" (feature films, not interviews or trailers).
- 3Fuzzy matching catches typos — "Merci Johson" still finds her.
- 4Recency weighting bubbles her newer films above her back catalogue.
The same query that returned zero results in v1 now returns the right films, in the right order. No exact-title typing required.
The result
A search bar that handles typos, understands context, and respects popularity. Users don't need to know the exact title. They search the way they think, and the system meets them there. Searches that used to return nothing started returning the right films, and the zero-result rate dropped sharply in the week after launch.
Takeaway
Don't force users to speak the database's language. Build the infrastructure to understand theirs.
The wider lesson I took from this: every product has a moment where the user's mental model and the system's data model collide, and the user always loses. The fix isn't to retrain the user. It's to build the translation layer.
What I do now
I build every search interface I touch the same way now: assume users are typing intent, not keys, and design backwards from there. The query log is the spec.