Introduction
Users search for what they mean, not always what you indexed. Someone looking for "trainers" might expect running shoes; another searches "sofa" when your catalog says "couch." Synonyms in Elasticsearch: practical tips and trade-offs is where we bridge that semantic gap without reindexing every time marketing renames a feature. This guide walks you through implementing synonyms efficiently, knowing when to use them, and avoiding the pitfalls we've seen tank search relevance in production.
The Synonym Token Filter
Elasticsearch provides the synonym token filter, which maps one or more terms to another during tokenization. It works at index time or search time, each with distinct advantages. The filter accepts synonym rules in two formats: explicit mapping (foo => bar) or bidirectional equivalence (foo, bar, baz).
Here's a straightforward mapping:
{
"settings": {
"analysis": {
"filter": {
"my_synonyms": {
"type": "synonym",
"synonyms": [
"quick,fast,rapid",
"jumps => leaps",
"the quick brown fox => quick fox"
]
}
},
"analyzer": {
"my_analyzer": {
"tokenizer": "standard",
"filter": ["lowercase", "my_synonyms"]
}
}
}
},
"mappings": {
"properties": {
"title": {
"type": "text",
"analyzer": "my_analyzer"
}
}
}
}The first rule creates a bidirectional map: searching for "quick," "fast," or "rapid" will all match documents containing any of those terms. The second rule is directional: "jumps" becomes "leaps," but not vice versa. The third handles multi-word synonyms, useful for colloquial product names.
However, index-time synonyms come with a cost. You expand the index size immediately, and any synonym list change requires a full reindex. For e-commerce platforms where product categories evolve monthly, this becomes a maintenance burden fast.
Search-Time Synonyms for Easy Updates
Search-time synonyms apply the filter only during query parsing, not during indexing. The indexed terms stay lean, and you can update synonyms without reindexing. This is the approach we recommend for most teams managing live catalogs.
Define the same filter but apply it to the query analyzer separately:
{
"settings": {
"analysis": {
"filter": {
"search_synonyms": {
"type": "synonym",
"synonyms": [
"laptop,notebook",
"mobile,smartphone,cell phone",
"gpu => graphics card"
]
}
},
"analyzer": {
"index_analyzer": {
"tokenizer": "standard",
"filter": ["lowercase"]
},
"search_analyzer": {
"tokenizer": "standard",
"filter": ["lowercase", "search_synonyms"]
}
}
}
},
"mappings": {
"properties": {
"product_name": {
"type": "text",
"analyzer": "index_analyzer",
"search_analyzer": "search_analyzer"
}
}
}
}Now when a user searches for "notebook," Elasticsearch expands the query to match "laptop" or "notebook" at query time. The indexed terms contain neither expansion. Update the synonym list in Elasticsearch settings (via index reload) or manage it in a synonym file updated on disk and picked up by Elasticsearch on index reopening.
We've run this pattern in production e-commerce environments where seasonal product names change. A bike retailer renames "road bikes" to "performance bikes" in Q4; instead of a full reindex, we update the synonym file and refresh. Queries still surface the right products for users accustomed to old terminology.
Keep Lists Curated
The temptation to throw every conceivable synonym into the filter is strong and dangerous. Unvetted synonym lists destroy relevance. Consider a SaaS team that added "invoice, bill, statement" as synonyms. Users searching "statement" began seeing invoicing workflows when they meant financial statements, tanking task discovery.
Curate synonyms around actual user behavior and business goals:
- Validate with search logs. Extract queries that returned zero results or clicked irrelevant results. If multiple users search "couch" and click on sofas, that's a genuine synonym. If one user searches "couch" and you guess they want something else, you're guessing.
- Scope by context. A furniture store's "sofa, couch" synonym differs from a dev tools platform where "sofa" might be an acronym. Use separate fields or analyzers if contexts diverge.
- Test bidirectional vs. directional. "Laptop => notebook" (directional) means "notebook" queries don't expand to "laptop." This is useful if "notebook" is a distinct product category you want to protect. Bidirectional expansions should be truly interchangeable.
- Limit scope. If you have 10,000 products, don't maintain 5,000 synonym rules. Prioritize top 50 searches and high-value mismatches. Smaller lists are easier to maintain and less likely to create surprising interactions.
Document why each synonym exists. A simple comment or a metadata tag in your synonym file ("added 2024-03-15, addresses top 10 zero-result queries") helps the next engineer understand intent and decide if it's still valid.
Test with _analyze
Before pushing synonyms to production, use the _analyze API to inspect how terms tokenize and expand. This is your safety net.
POST /my_index/_analyze
{
"analyzer": "search_analyzer",
"text": "I need a fast laptop"
}Response shows each token after synonyms are applied:
{
"tokens": [
{ "token": "i", "position": 0 },
{ "token": "need", "position": 1 },
{ "token": "a", "position": 2 },
{ "token": "fast", "position": 3 },
{ "token": "rapid", "position": 4 },
{ "token": "quick", "position": 5 },
{ "token": "laptop", "position": 6 },
{ "token": "notebook", "position": 7 }
]
}Notice "fast" expanded to "rapid" and "quick" (bidirectional synonyms), and "laptop" expanded to "notebook." If you see unexpected expansions, your synonym rules are ambiguous or conflicting.
Test edge cases: multi-word synonyms, overlapping rules, special characters. A synonym rule like "c++ => cpp" might fail if your tokenizer doesn't preserve "+". Test it:
POST /my_index/_analyze
{
"analyzer": "search_analyzer",
"text": "c++ programming"
}If it doesn't expand as expected, adjust your tokenizer (e.g., use pattern or ngram tokenizer) or the synonym format.
Common Mistakes
- Over-synonymizing. Adding "apple => fruit" makes fruit searches return Apple Inc. product pages. Synonyms must be semantically tight within your domain.
- Ignoring performance cost. Search-time synonym expansion increases query complexity. A query "shoe" that expands to ten synonyms becomes an OR query with ten terms. Monitor query latency when rolling out new synonyms at scale.
- Mixing index and search time without clarity. If you apply synonyms at index time, applying them again at search time can cause over-expansion or conflicting logic. Choose one strategy per field.
- Not tracking synonym versions. Store your synonym file in version control. Without history, you can't debug when relevance suddenly degrades after a synonym update.
- Using synonyms as a band-aid for schema design. If you're adding 50 synonyms to make a poorly-structured product taxonomy work, redesign the taxonomy first. Synonyms are tactical, not strategic fixes.
Key Takeaways
- Use the
synonymtoken filter with search-time application for most production systems; it avoids reindexing and keeps your indexed data lean. - Validate synonyms against real user search behavior; avoid guessing at semantic equivalence.
- Use
_analyzeto inspect tokenization and expansion before deploying to production. - Keep synonym lists small and curated. Every rule adds maintenance burden and potential for unexpected query expansion.
- Document why each synonym exists and track changes in version control.
- Monitor query latency after adding synonyms; expansion can increase query cost if rules are too broad.
- Bidirectional synonyms ("foo, bar") are for true equivalents; directional mappings ("foo => bar") preserve semantic boundaries when needed.






Comments
Loading comments…