Two synonym shapes. Three typo dials.
Multi-way equivalence or one-way expansion, push-to-engine on save. Per-index typo budget, prefix matching, configurable stop-words, Romanian-aware morphology — all wired through the same search params.
// Two synonym shapes, same table { "type": "multi_way", // symmetric "synonyms": ["phone", "smartphone", "mobile"], "enabled": true } { "type": "one_way", // expansion "root": "trainers", "synonyms": ["sneakers", "runners"], "enabled": true }
Pick equivalence or expansion. No other knobs.
Skryx stores synonyms in one table with a type column. Either
they're symmetric (multi_way) or one-directional
(one_way). Every create / update / delete idempotently
re-pushes the full enabled-synonym list to the engine — DB and engine stay
in lockstep, with no drift.
Symmetric · true equivalence
All terms map to each other. ["phone", "smartphone", "mobile"]
means a search for any of the three retrieves products tagged with any of
the three. root is null.
Expansion · directional
root expands to synonyms[], but not vice versa.
Searches for "trainers" also retrieve "sneakers" and "runners"; searches
for "sneakers" don't pull in "trainers". Good for typo aliases and
regional terms.
Catalog-validated. Not LLM-hallucinated.
Two separate flows feed Skryx's synonym table from analytics. Both surface in AI Coach as one-click recommendations. Both verify the suggestion against your actual catalog before showing it.
Singular ⇄ plural from real index tokens.
GenerateCatalogSynonymsJob walks your index, extracts
title tokens that appear ≥ 2× and are ≥ 4 chars long, drops stopwords,
and runs each through the Romanian morphology service to detect form
and generate the opposite. A pair only survives if both forms
appear in your top 2,000 frequent words.
- 171 hand-curated irregular plurals + regular suffix rules
- Confidence ≥ 0.85 required to surface
- Up to 100 pairs in one Coach card, applied per-pair via checkboxes
- Romanian today; English and other languages on the roadmap
Skryx AI reads zero-result queries.
AI Coach (separate flow) looks at zero-result and low-CTR queries against your catalog sample and asks Skryx AI for synonym pairs to fix the gap. Output is post-filtered against your enabled synonyms and normalised for diacritics so already-applied pairs never come back.
- Conservative prompt: "only suggest if the catalog clearly has the target"
- 30-day cooldown on dismissed terms
- One-click apply creates a
multi_wayrow and syncs to engine
{
"type": "missing_synonym",
"confidence": "high",
"search_count": 24,
"payload": {
"root": "trainers",
"synonyms": ["sneakers", "runners"],
"reason": "0 hits · catalog has 142 sneaker SKUs"
}
}
Three dials. Per index. Per query.
Stored as a JSON config on the index. Sensible defaults shipped out of the
box; tenants override per index in the Search Settings UI, or per query via
num_typos in the request body.
2 typos. Length floors that prevent nonsense.
Defaults: num_typos = 2, min_word_length_for_1_typo = 4,
min_word_length_for_2_typos = 7. Short tokens (1–3 chars) get
zero tolerance — a typo on "ipad" should not return "iped" — and the
full 2-typo budget only unlocks on long words where it's actually safe.
- Configured in
indexes.typo_configJSON - Per-query override via the
num_typosrequest param - Engine-side: budget applies uniformly across searchable fields
{
"num_typos": 2,
"min_word_length_for_1_typo": 4,
"min_word_length_for_2_typos": 7
}
// Behaviour:
"ip" → 0 typos allowed
"iphn" → 1 typo allowed (4 chars)
"iphone" → 1 typo allowed (6 chars)
"iphonr5" → 2 typos allowed (7 chars)
On by default. Disable per query if you need to.
Skryx passes prefix=true on every query unless the caller
explicitly sets prefix=false. Critical for
instant-search-as-you-type UIs where the customer hasn't finished
typing yet.
- Default:
truefor every query - Per-query override via the
prefixrequest param - Combines with typo tolerance — "iphn" + prefix matches "iPhone"
Strip the noise before it hits the engine.
Per-index stop_words JSON array. Skryx removes any word in
the list from the query before sending it to the engine — no
weight wasted on connectives like "the", "and", "for" when they don't
carry intent.
- Configured per index, edited from Search Settings
- Romanian Coach prompts seed a working list of e-commerce noise (units, sizes, dimensions)
- Bypassable per query: pass the raw query and Skryx still strips the configured words
{
"stop_words": [
"the", "a", "an",
"for", "with", "in",
"kg", "mm", "cm"
]
}
// "headphones for the office" →
// engine sees: "headphones office"
"Showing results for X" when AI rewrote the query.
Synonym and typo expansion happen inside the engine — they don't surface
separately in the API response. AI-driven query rewrites (from the
Query Understanding step) do come back to your UI: the response includes
ai_context.original_query, ai_context.rewritten_query,
and a list of suggestions for "Did you mean?" banners.
{
"hits": [ /* … */ ],
"found": 142,
"search_mode": "hybrid",
"ai_enhanced": true,
"ai_context": {
"original_query": "laptop for vid edting",
"rewritten_query": "laptop for video editing",
"intent": "compare",
"alternative_queries": [
"4k editing laptop",
"creator laptop"
]
},
"suggestions": ["video editing laptops"]
}
Render exactly what the customer expects.
Use original_query vs rewritten_query to render
"Showing results for laptop for video editing" when they
differ. Use suggestions[] for the "Did you mean?" row.
Use ai_context.intent if you want to render different UI
for purchase-intent vs problem-intent queries.
- Always present, even when no rewrite happened (both fields equal)
ai_enhanced: falseflag tells the UI to skip the banner- Same payload shape for keyword / semantic / hybrid modes