Built offline
Everything your serving tier reads gets built offline, and that pipeline is classic batch processing.
Stream query logs into storage as people search. Then periodically, daily is common, run a job that aggregates counts over a trailing window, weighting recent days higher so last year's fads decay away.
Let a filtering stage earn its keep next. Drop queries below a frequency floor, collapse near-duplicates and normalise case, and run the blocklist for offensive and legally sensitive suggestions.
Take that last one seriously, because it is the stage that generates actual news stories when it fails.
Feed the survivors to your builder, which computes every node's list and emits an immutable snapshot. Your serving machines pull it and swap.
The flaw in a daily batch
Face the flaw built into a daily batch: it is up to 24 hours behind reality. Most of the time nobody notices, because the top suggestions for an everyday word are identical every day.
Watch it fail during breaking news. An earthquake, a transfer rumour, a death, and the freshest queries are exactly the ones people want, and your batch has never heard of them.
Split the problem instead of making your big structure mutable. Run a streaming job counting queries over short windows, flagging terms whose rate spikes against their baseline.
Put those trending candidates into a small separate structure that rebuilds every few minutes, holding tens of thousands of entries rather than millions.
Read both at query time, merge them, and let a trending hit displace your weakest batch suggestion. Your heavyweight structure stays immutable and easy to reason about, and your volatile one stays small enough to rebuild constantly.
Add personalisation the same way if the product needs it. Recent searches from somebody's own history, merged in front of the global results.
Keep it a layer, whatever you do. Baking per-user data into the shared structure multiplies it by your user count. That is the fastest way to stop it fitting in memory.
Worked example
During the 2023 transfer window, a sports site's autocomplete becomes a running joke: the day Jude Bellingham signs with Real Madrid, typing 'bell' still suggests last season's queries, and the signing everyone is searching for surfaces 26 hours later when the nightly Spark job catches up. Engagement data backs the mockery: suggestion click-through on trending days drops from 34 percent to 19. Marta's team adds a streaming layer: search events flow through Kafka into a Flink job computing 10-minute windowed counts, and any query whose velocity jumps 20x over its 7-day baseline enters a trending set, rebuilt every 5 minutes and capped at 50,000 entries. The merge rule is one line: a trending match replaces the fifth-ranked batch suggestion. The next big signing shows up in suggestions 11 minutes after the news breaks.