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

> Drop wildcard for autocomplete; build the prefixes at index time with edge_ngram and keep a standard search analyzer so a keystroke is a plain term lookup.

- Asked: 2026-05-23
- Answered: 2026-05-26
- Asked by: Efe
- Tags: performans, elasticsearch, veritabani
- Source: https://muhammetsafak.com/just-ask/search-as-you-type-performance-with-edge-ngram-in-elasticsearch/
- Language: en-US
- Author: Muhammet Şafak

---
**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?


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.

## Short answer

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. For an introduction to Elasticsearch's indexing and analysis model, see [getting started with Elasticsearch and Kibana](/blog/getting-started-with-big-data-using-elasticsearch-and-kibana/).

## Why

1. **The gap between a scan and a lookup is a gap in scale.** `edge_ngram` emits every prefix of a word ("a", "ay", "ayk", "ayka"…) as separate tokens at index time; when the user types "ayk" there's no scan, the token is looked up directly. All the speed of as-you-type comes from here.

2. **The most common mistake is not separating the analyzers.** If you ngram the query too, every prefix the user types gets re-split, producing irrelevant matches and inflated scores.

3. **Ngrams inflate the index.** Keeping the gram range wide pays back the speed you gained in disk and RAM.

## What to do

1. **Apply `edge_ngram` only on the index side.** Let `analyzer` build ngrams at index time and `search_analyzer` stay standard on the search side. The index builds the prefixes, the search just matches them.

2. **For Turkish, add `lowercase` + `asciifolding`.** Put these before the ngram in your custom analyzer so "Şişe" matches "sise" and "Ürün" matches "urun". On a Turkish search bar this isn't negotiable.

3. **Keep `min_gram`/`max_gram` tight** (e.g. 2-15) and limit which fields are searched.

4. **Add debounce on the client** (e.g. 150 ms); don't fire a request on every keystroke.

5. **Consider the shortcut.** ES's `search_as_you_type` field type 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, every keystroke becomes a plain term lookup instead of a scan across 10M products.

## Related Reading

- [When should I switch to a covering index with INCLUDE to get an index-only scan?](https://muhammetsafak.com/just-ask/switch-covering-index-include-get-index-only-scan/) — Just Ask
- [Should I use a partial index on a queue table where I only ever scan 'pending' rows?](https://muhammetsafak.com/just-ask/should-i-use-a-partial-index-on-a-queue-table-where/) — Just Ask
- [Why should I use a Sorted Set for a live leaderboard in Redis?](https://muhammetsafak.com/just-ask/redis-data-types-using-sorted-sets-for-a-leaderboard/) — Just Ask
