Real users type “elasitcsearch” instead of “elasticsearch”. And they expect us to know they meant the latter. These two queries solve the “typos and multiple fields” problems.
Fuzzy query — handling typos
In simple language — “find docs where the term is almost equal to my search term, allowing for N character edits.” That’s Levenshtein distance.
Levenshtein distance = number of single-character edits (insertions, deletions, substitutions) needed to turn one string into another. cat → bat is distance 1. cat → bats is distance 2.
GET /products/_search
{
"query": {
"fuzzy": {
"title": {
"value": "elasitcsearch",
"fuzziness": "AUTO"
}
}
}
}
fuzziness options:
0— exact match (no fuzziness, same as term).1or2— explicit edit distance.AUTO— smart default based on term length:- 0-2 chars → 0 edits (must be exact)
- 3-5 chars → 1 edit
- 6+ chars → 2 edits
AUTO is what we want 99% of the time. Short terms shouldn’t allow typos (too many false positives).
Fuzzy inside match
The fuzzy query operates on a single term. For multi-word fuzzy search, use match with fuzziness:
GET /products/_search
{
"query": {
"match": {
"title": {
"query": "wirless headfones",
"fuzziness": "AUTO"
}
}
}
}
This finds “wireless headphones” even with two typos. Each word gets its own fuzziness allowance.
Multi-match query — search across fields
In simple language — “search this text across multiple fields at once.” It’s the realistic version of any search bar that searches title + description + tags + author all together.
GET /products/_search
{
"query": {
"multi_match": {
"query": "wireless headphones",
"fields": ["title", "description", "tags"]
}
}
}
Field boosting
We rarely want all fields treated equally. A match in the title should count more than a match in the description. Use ^N suffix:
{
"multi_match": {
"query": "wireless headphones",
"fields": ["title^3", "description^1", "tags^2"]
}
}
Now a match in title scores 3x more than the same match in description. This dramatically improves relevance for real search bars.
Multi-match types
The type parameter controls how scores from different fields are combined:
| Type | What it does | When to use |
|---|---|---|
best_fields (default) | Use the score of the single best matching field | Most search bars |
most_fields | Sum scores across all matching fields | When the same text in multiple fields is a stronger signal |
cross_fields | Treat fields as one big field (good for names split into first/last) | People search, addresses |
phrase | Each field tried as a phrase match | Exact phrase across fields |
phrase_prefix | Phrase match with prefix on last term | Autocomplete |
{
"multi_match": {
"query": "manish prajapati",
"type": "cross_fields",
"fields": ["first_name", "last_name"],
"operator": "and"
}
}
cross_fields is perfect here — “manish” matches first_name, “prajapati” matches last_name, but together they should look like a single match.
Combining with fuzziness
We can do both — multi-field AND typo-tolerant:
GET /products/_search
{
"query": {
"multi_match": {
"query": "wirless headfones",
"fields": ["title^3", "description"],
"fuzziness": "AUTO"
}
}
}
This is the “kitchen sink” search bar query. Multi-field, weighted, typo-tolerant.
Performance note
Fuzzy queries are expensive — ES has to compute edit distances against many terms in the index. Two safeguards:
prefix_length— number of leading characters that must match exactly (default 0). Settingprefix_length: 1or2massively narrows the candidate set.max_expansions— caps the number of terms the query expands to (default 50).
{
"fuzzy": {
"title": {
"value": "elasticsearch",
"fuzziness": "AUTO",
"prefix_length": 2,
"max_expansions": 100
}
}
}
Quick rules
- User-facing search bars →
multi_match+ field boosts +fuzziness: AUTO. Best UX. - People/name search →
cross_fieldstype. - Autocomplete →
phrase_prefixtype (or a dedicated suggester). - Short queries (< 3 chars) — disable fuzziness, too noisy.
- Always set
prefix_length: 1in production fuzzy queries for performance.