Case studies
Offline query aggregation
How autocomplete scores come from batch counts of query logs, with a streaming overlay for trending phrases and versioned trie snapshots that can roll back.
Autocomplete suggestions are not built from live searches. A batch job counts past queries, applies decay so old popularity fades, and publishes a new trie. A streaming job adds a small overlay for phrases that spike between batch runs. Together they give stable rankings and fresh trends.
Concept
Before you start
- Batch job: a job that processes a large set of stored data on a schedule.
- Stream job: a job that processes events as they arrive. See batch and stream processing.
The big idea
A newspaper's "most read this week" box is rebuilt on a schedule. A breaking-news line can be added between editions. The box is mostly stable, and the breaking-news line stays fresh.
The analogy stops at one point. A printed box cannot be corrected in the middle of an edition. Here, a versioned snapshot can be swapped in at any time, and swapped back out if it is bad.
Walking through it
The pipeline has five steps.
- Collect logs of successful searches. Aborted prefixes are noise.
- Run a batch job that counts each query and applies time decay to produce
(query, score). - Run a stream job that tracks velocity over the last hour and boosts trending queries into a small overlay.
- Build the trie from the merged scores and publish it as a versioned file.
- Merge at build time:
finalScore = historical + trendingBoost.
Here is a worked case. The query apple has 9.1 million searches in 28 days. A typo, aple, has 12,000. If apple event spikes this afternoon with no history, its trending boost can push it into the top five for apple before tomorrow's batch run. The boost value is made up for this example, but the mechanism is what matters.
Log hygiene
Bots and internal test searches can flood the logs. Filter them out before counting: keep only authenticated users, drop traffic with low bot scores, and require a minimum click rate on results. Scrub anything that looks like an email address or a raw ID. Otherwise the trie learns those strings and suggests them.
Shipping the artifact
Serving hosts pull an immutable snapshot from object storage and check its checksum. They load the new version, then switch traffic in one atomic step. A rollout can start with a canary set of shards. Rolling back means pointing traffic at the previous snapshot key. Hosts keep the old version until the new one is confirmed.
Common mistakes
- Rebuilding from raw logs per request. The build runs on a schedule, and serving only reads.
- Letting bot traffic into the counts. Bots decide what your users see.
- Editing a live trie in place. A half-updated trie can serve mixed results. Use versioned snapshots.
- Mixing languages in one trie. Build one trie per locale or market.
Check yourself
1. A query goes viral at 10:00, but the nightly batch runs at 02:00. How does it appear in suggestions before then?
Answer: The streaming overlay boosts it into the top results within minutes, without waiting for the rebuild.
2. Why keep the previous snapshot on the serving hosts?
Answer: If the new build is bad, you can point traffic back to the old version immediately.
Key takeaways
- Popularity comes from batch counts; freshness comes from a streaming overlay.
- Filter bots and sensitive strings before counting, or the suggestions learn them.
- Publish versioned snapshots and swap them atomically, with rollback one pointer away.
- Keep a separate trie for each locale.
Further learning
Next, see how the latency target is met in the keystroke latency budget.
Related
Case study: search autocomplete
Typeahead under 100 ms: tries with cached top-k, offline query-log aggregation, prefix sharding and client debouncing.
Prefix top-k trie
A trie stores strings by shared prefixes, and each node can keep its best completions. A lookup walks the prefix and reads one list, no matter how many queries exist.
Batch and stream processing
How to move and transform large data sets reliably. Batch jobs run over bounded data, streams run over events as they arrive, and the same ideas of time, state and idempotent writes apply to both.