Build the mental model
The `match` query from Lesson 6 onward analyzes a user's full search term before matching documents — it isn't optimized to feel real-time responsive while the user is typing character by character ("re", "red", "redi"...). There are two approaches to implementing autocomplete or search-as-you-type UX in Elasticsearch: (1) the `completion` suggester, which pre-builds a dedicated data structure (an in-memory FST — finite state transducer) specifically for suggestion fields, giving extremely fast prefix matching (sub-millisecond), but requiring a somewhat specialized setup (`type: completion` mapping, structured input format); (2) the `search_as_you_type` field type, which pre-computes edge n-grams (prefix substrings) at index time on a text field, queryable with a regular `match_bool_prefix` query — not as raw-fast as the `completion` suggester, but simpler to set up and easier to combine with regular fields. This site's existing SearchAutocomplete feature (client-side filtering over a local in-memory JSON index) feels instant while the tutorial count is small, but as tutorial count grows (this Elasticsearch course being one of these 25 tutorials itself), a growing client-side JSON payload starts hurting initial load time too — a server-side Elasticsearch suggester instead returns just a small candidate list per query, keeping the client-side payload size constant. This project transplants a real feature of this very site onto a production-grade backend.
Connect it to a real scenario
Implement the Tutorial Platform's search box with the `search_as_you_type` field type (`titleSuggest`) — add a `titleSuggest` sub-field alongside the regular `title` text mapping, and send a `match_bool_prefix` query for every keystroke the user types, limiting the response candidate count to around `size: 5` so the dropdown UI doesn't overflow. Add debouncing on the frontend (say 150ms) — sending a request on every single keystroke would create unnecessary load. Replace the existing client-side local-JSON SearchAutocomplete component with a version that calls this server-side endpoint instead — the UX should feel essentially unchanged to the user.
Try the working example
// Mapping addition
// "titleSuggest": { "type": "search_as_you_type" }
async function suggestTitles(prefix: string) {
const result = await esClient.search({
index: 'tutorials',
size: 5,
query: {
match_bool_prefix: { titleSuggest: prefix },
},
});
return result.hits.hits.map((hit) => (hit._source as { title: string }).title);
}
// debounce on the client before calling this per keystrokeAs soon as a user types "redi", you get a dropdown list of up to 5 candidate titles like "Redis Basics" and "Redis Caching Strategies".5-minute try-it
Write how the mapping would change (field type, input format) to use the `completion` suggester approach instead, and compare its setup complexity with the `search_as_you_type` approach.
One important caution
Sending a request per keystroke without debouncing — a single user typing can create unnecessary load with many requests hitting the Elasticsearch cluster.
Not limiting the autocomplete response candidate count (leaving `size` at its default) — too many results in the dropdown UI hurts the user experience and needlessly bloats the response payload.
Elasticsearch Guide — Search-as-You-Type — Elastic