Skip to content
Muhammet Şafak
tr
Asked by: Efe Answered:

How do I make search-as-you-type fast with edge n-grams in Elasticsearch?


Question

On our e-commerce search bar, every keystroke fires a query against Elasticsearch, and we have 10M+ products. The `wildcard`/`regexp` queries send CPU through the roof and latency climbs. How should I set up the `Edge N-gram` tokenizer and index-time analysis in Elasticsearch to get search down to milliseconds?

Answer

Short answer: drop wildcard/regexp; move the work from query time to index time — build the prefixes when you index with edge_ngram so autocomplete becomes a plain term lookup.

Here’s the real issue: wildcard/regexp are scans that run at query time; they can’t use the inverted index efficiently, so on every keystroke they try to filter 10M documents and burn CPU. The fix isn’t to speed up the query, it’s to do the work ahead of time.

  1. Shift the cost to index time. The edge_ngram token filter emits every prefix of a word (“a”, “ay”, “ayk”, “ayka”…) as separate tokens when you index. When the user types “ayk” there’s no scan anymore; the “ayk” token is looked up directly — an ordinary term lookup that takes milliseconds. All the speed of as-you-type comes from here.
  2. SEPARATE the index analyzer from the search analyzer. This is the most common mistake. Apply edge_ngram only on the index side (analyzer); use a standard analyzer on the search side (search_analyzer). If you ngram the query too, every prefix the user types gets re-split, producing irrelevant matches (noise) and inflated scores. The index builds the prefixes, the search just matches them.
  3. For Turkish, add lowercase + asciifolding. Put these filters before the ngram in your custom analyzer so “Şişe” matches “sise” and “Ürün” matches “urun”. Even if the user types without accents, they still find the result — on a Turkish search bar this isn’t negotiable.
  4. Cap index growth and noise. Keep min_gram/max_gram tight (e.g. 2-15); otherwise the index balloons exponentially. Limit which fields are searched, and debounce on the client (e.g. 150 ms) so you don’t fire a request on every keystroke. Optional shortcut: use ES’s search_as_you_type field type — it sets this up (edge ngram + shingle) for you.

Bottom line: I’d build autocomplete at index time, either with a custom edge_ngram analyzer or the ready-made search_as_you_type field; I’d never use wildcard for autocomplete. Ngram + lowercase + asciifolding on the index analyzer, standard matching on the search analyzer, keep the gram range tight, and add debounce on the client. Done right, search across 10M products drops to milliseconds per keystroke.

Tags: #performance#elasticsearch#database
Share:

Comments

Sign in with your GitHub account to join the discussion. Comments are stored in GitHub Discussions.

More Questions

All questions

Search the site

Start typing to search posts, projects and pages.

Esc to close Powered by Pagefind