Keyword search matches the words a shopper typed. Semantic search matches what they meant. "Something for post-workout recovery" shares no words with "whey hydrolysate", yet a good store should connect them — and that is the gap embeddings fill. But semantic search is also the feature most often deployed badly, running on every query and returning confident nonsense. This is the intuition merchants need, the hybrid architecture we run, and the discipline that keeps vectors from doing harm.
The intuition: meaning becomes geometry
An embedding is a model's way of turning a piece of text — a product, a query — into a long list of numbers that positions it in a high-dimensional space. The only property that matters to a merchant is this: things that mean similar things land near each other. Whey hydrolysate, casein and a recovery blend cluster together not because they share words but because the model learned they occupy similar territory. A query gets embedded the same way, and semantic retrieval is simply "find the products nearest to this query in that space". This is why it rescues intent phrasing, long natural-language queries and cross-language searches: nearness survives the absence of shared words, and it partly survives a change of language.
The flip side is the property that makes it dangerous. There is always a nearest neighbour. Semantic search never returns nothing — ask it for a brand you do not carry and it returns the closest thing it has, with no signal that it missed. Keyword search, for all its literalness, at least knows when it has failed.
Two practical points follow from this geometry. First, the embedding is only as good as the text you embed — a product with a thin, generic description lands in a vague part of the space and matches vaguely, so enrichment quality caps semantic quality. Second, dimensionality and model choice matter less than merchants fear: a solid general-purpose embedding model is enough for most catalogues, and the returns from a fancier model are usually smaller than the returns from better product text feeding the one you already have.
The hybrid: keyword and vectors, fused
Because each layer fails where the other is strong, we run both. A keyword engine handles lexical matching with typo tolerance and facets; a vector database holds product embeddings for semantic retrieval. Each returns a ranked list, and we merge them with reciprocal rank fusion — a simple, robust method that rewards products ranked well by both layers without needing the two scores to be comparable to each other. RRF is deliberately boring: it takes each product's rank in each list, not its raw score, so a keyword relevance number and a vector distance never have to be reconciled on the same scale. The architecture overview covers how the two engines sit in the request path; this article is about when the semantic half should fire at all.
| Query | Keyword layer | Semantic layer | Should win |
|---|---|---|---|
| Brand or SKU | Exact, fast | Returns look-alikes | Keyword |
| Product name | Strong | Fine | Keyword |
| Category word ("protein") | Strong | Fine | Keyword, permissive |
| Intent phrase ("for recovery") | Misses | Strong | Semantic |
| Long natural-language query | Weak | Strong | Fused |
| Cross-language / Cyrillic | Misses | Strong | Semantic plus synonyms |
Trigger the semantic layer selectively
The single most important decision in a hybrid system is not the fusion algorithm — it is when to run embeddings at all. Running them on every keystroke is wasteful and often harmful, because for the majority of ecommerce queries (a name, a brand, a category word) the keyword layer is already correct and cheaper, and the semantic layer can only add look-alikes. We trigger the vector layer selectively.
Our semantic layer fires on signals, not by default: longer queries of several tokens; intent-shaped phrasing like "similar to", "alternative" or "for…"; cross-language signals such as Cyrillic characters or local diacritics in a mostly-English index; and weak lexical recall, where the keyword layer came back thin and semantics get a chance to fill in. Short, precise queries stay purely lexical.
Why always-on semantic hurts
An always-on semantic layer degrades exactly the queries a store most needs to get right. Type an exact brand and it dilutes the exact match with plausible substitutes. Type a SKU and it retrieves the nearest catalogue vector rather than admitting no match. Worst of all, it destroys the honest empty state: a store that can say "we don't carry this brand" is more trustworthy than one that always produces a full grid of approximate answers. "No results, but here are alternatives" is sometimes the correct answer, and only a system that can decline to match can give it.
The subtler cost of always-on semantics is that it hides your catalogue gaps. If every query returns a full grid, your zero-result rate collapses toward zero and you lose the single best signal about what shoppers want and cannot find. A store that lets search fail honestly keeps that signal; a store that papers over every miss with a nearest neighbour is flying blind about its own demand.
Two ranking guards worth adding
Selective triggering decides whether semantics run; two guards decide what survives. The first is an adaptive minimum relevance score that grows with query length. A one-word query like "protein" should be permissive — the shopper wants the category. A five-word query is specific, and weak matches should be cut rather than padded to fill a grid. A fixed threshold cannot serve both; one that scales with token count can. The second is variant collapsing: semantic retrieval loves to return six near-identical vectors from one variant family, so a distinct-on-parent rule keeps page one diverse.
Keep the cost sane
Vectors cost more than keyword lookups — embedding the query, the vector search, the fusion. Selective triggering is the primary cost control: if only a minority of queries invoke the semantic layer, the average query stays cheap. Two more habits help. Embed products once at index time, not per query, so the expensive work is amortised across every search. And push understanding into the index through enrichment — enriched searchable text and per-product synonyms let the cheap keyword layer answer queries that would otherwise fall through to vectors. The same "ground answers in your catalogue" thinking underpins retrieval for AI assistants; semantic search is that idea applied to the search box.
There is a latency budget to defend as well as a money budget. The vector round-trip and the fusion step add milliseconds, and on a mobile connection those milliseconds are felt. Selective triggering protects latency for the same reason it protects cost: the common, cheap, lexical queries never pay the semantic tax, so your median search stays fast and only the queries that genuinely need meaning-matching spend the extra time.
Key takeaways
- Embeddings turn meaning into geometry — products that mean similar things sit near each other, which is why vectors rescue intent and cross-language queries.
- There is always a nearest neighbour, so semantic search never returns nothing — powerful, but it destroys the honest empty state if left unchecked.
- Run a hybrid and fuse with reciprocal rank fusion, which merges lists by rank so incomparable scores never have to be reconciled.
- Trigger the semantic layer selectively — on long, intent-shaped, cross-language or weak-recall queries — not on every keystroke.
- Add an adaptive relevance threshold and variant collapsing so specific queries are strict and page one stays diverse.
- Control cost by embedding at index time and enriching the keyword layer so most queries never need vectors at all.
Frequently asked questions
What is semantic search in ecommerce?
Is semantic search better than keyword search?
What is reciprocal rank fusion?
Do I need a vector database for ecommerce search?
Hybrid search, tuned to trigger only when it should.
Keyword plus vectors with reciprocal rank fusion and selective triggering ships as part of the marketplace we run on sites that already have traffic.
Request early access Try an intent query live →