MindForge
MindForge
DashboardHelp & Support
Dashboard
MindForge

Interview Preparation Bootcamp

Course progress

0%
0 of 177 modules complete
Start Here0/1
  • How to Use This Course
Data Structures & Algorithms0/27
  • Arrays and Hashing
  • Two Pointers
  • Sliding Window
  • Sliding Window: Harder Problems
  • Binary Search
  • Stacks
  • Practice Test: Arrays, Pointers, Windows, Search and Stacks
  • Trees: Traversals and Core Patterns
  • Binary Search Trees and Rebuilding a Tree
  • Tries (Prefix Trees)
  • Heaps and Priority Queues
  • Graphs: BFS and DFS
  • Topological Sort and Cycle Detection
  • Union-Find (Disjoint Set Union)
  • Practice Test: Trees, Heaps and Graphs
  • Dynamic Programming Basics
  • Dynamic Programming: Two Dimensions
  • Dynamic Programming: Hard String Matching
  • Backtracking
  • Backtracking: Constraint Satisfaction
  • Greedy Algorithms
  • Interval Problems
  • Bit Manipulation
  • Math and Geometry
  • String Manipulation
  • Pattern Recall and Mock Coding Rounds
  • Practice Test: DP, Backtracking, Greedy and More

System Design

Foundations0/16
  • The System Design Interview Framework
  • Back-of-the-Envelope Estimation
  • Networking and Protocols for Design
  • API Design and Idempotency
  • Load Balancing, Proxies, and Scaling Out
  • Caching and CDNs
  • Choosing a Database: Storage, Indexes and Transactions
  • Replication, Partitioning, and Sharding
  • CAP, PACELC, and Levels of Consistency
  • Messaging, Queues, and Event-Driven Architecture
  • Distributed Transactions and Data Integrity
  • Coordination, Consensus, and Distributed Locks
  • Reliability, Resilience, and Rate Limiting
  • Observability, Security, and Cost
  • System Design Cheat Sheet
  • Practice Test: System Design Foundations
Case Studies0/23
  • Design a URL Shortener
  • Design a Rate Limiter
  • Design a Notification Service
  • Design a Job Queue System
  • Design a Chat App (WhatsApp)
  • Design an Analytics Pipeline
  • Design a Multi-tenant SaaS Architecture
  • Design a Social Media Feed (Twitter/X)
  • Design a Search Autocomplete System
  • Design a File Storage Service (Dropbox)
  • Design Google Docs
  • Design a Code Review System
  • Design Netflix
  • Design YouTube
  • Design Spotify
  • Design Uber/Lyft
  • Design Airbnb
  • Design Ticketmaster (Eventbrite)
  • Design an E-commerce Cart, Checkout, and Catalog
  • Design a Payment System
  • Design a Logging and Monitoring System
  • Mock Design Rounds
  • Practice Test: System Design Case Studies
Low-Level Design0/19
  • The LLD Interview Framework and UML
  • OOP Foundations for Design
  • SOLID Principles
  • Creational Patterns
  • Structural Patterns
  • Behavioral Patterns I — Strategy, Observer, Command, State, Template Method
  • Behavioral Patterns II and Anti-Patterns
  • Concurrency in Low-Level Design
  • Design a Parking Lot
  • Design an Elevator System
  • Design a Movie Ticket Booking System
  • Design an Expense-Sharing App (Splitwise)
  • Design a Vending Machine and an ATM
  • Design a Rate Limiter and a Logging Framework
  • Design a Notification Service and an In-Memory Cache
  • Design Games — Tic-Tac-Toe, Snake and Ladder, Chess
  • Database Design for LLD
  • LLD Cheat Sheet and Recall Drill
  • Practice Test: Low-Level Design

Backend

Python0/5
  • How Python Runs Your Code
  • Functions Deep Dive: Closures, Generators, Context Managers, Scope
  • Classes Deep Dive: Method Types, MRO, Metaclasses
  • Standard Library and Serialization
  • Practice Test: Python
Django0/6
  • Django Request Lifecycle
  • Lab: Django Middleware — Request ID & Response Time
  • Django ORM and Querysets
  • Django's Cache Framework
  • Practice Test: Django
  • Django in Production: Debugging Labs
FastAPI0/5
  • FastAPI, ASGI, and Async
  • FastAPI Dependency Injection
  • FastAPI Background Tasks
  • Lab: FastAPI Async — Concurrent Aggregation
  • Practice Test: FastAPI
Databases (PostgreSQL)0/6
  • Indexing
  • Query Optimization
  • Transactions and Isolation
  • Migrations and Schema Changes
  • Hierarchical Data and Safe Concurrent Updates
  • Practice Test: Databases
Caching, Queues & Distributed Systems0/8
  • Redis Caching
  • Redis Advanced Patterns
  • Celery and Background Workers
  • Kafka and Message Queues
  • Async Pipelines
  • Distributed Systems Basics
  • Distributed Locks
  • Practice Test: Caching, Queues and Distributed Systems
APIs, Security & Deployment0/9
  • REST API Design
  • API Versioning and Error Handling
  • API Security and Authentication
  • WebSockets and Real-Time Systems
  • Docker and Containers
  • File Storage with S3
  • Testing Strategies
  • Mock Backend Round
  • Practice Test: APIs, Security and Deployment
Frontend0/38
  • HTML Document Structure and Semantics
  • CSS Box Model, Flexbox and Grid
  • CSS Architecture and Theming
  • CSS and Rendering Performance
  • Variables, Scope, Hoisting, and Truthiness
  • Functions, this, and Binding
  • Objects and Prototypal Inheritance
  • JavaScript Utility Patterns: Cloning, Caching, and Memory
  • Promises From Scratch
  • The Event Loop and Browser Rendering Pipeline
  • The DOM: Nodes, Events, and Traversal
  • Practice Test: HTML, CSS and JavaScript
  • React Rendering Fundamentals
  • React Hooks Internals
  • React Performance
  • Lab: React — Stateful Counter Component
  • State Management
  • State Machines in React
  • React Custom Hooks and Composition Patterns
  • TypeScript for React
  • React Testing
  • Practice Test: React
  • HTTP and Caching
  • Network Performance and Web Vitals
  • Code Splitting and Bundles
  • Virtualization
  • GraphQL and Data Fetching
  • Web Security
  • WebSockets and Real-time
  • SSR and Next.js
  • Micro-frontends
  • Build Tools and Bundling
  • Accessibility
  • Error Handling
  • Internationalization
  • Animation
  • Rapid Recall and Mock Frontend Rounds
  • Practice Test: Performance, Architecture and Production
Behavioral & Interview Day0/14
  • Resume and Project Walkthroughs
  • The STAR Method and Refining Your Stories
  • Conflict and Difficult Coworkers
  • Failures, Incidents, and Obstacles
  • Leadership, Mentorship, and Ownership
  • Teamwork, Communication, and Feedback
  • Growth and Handling Ambiguity
  • Career Goals, Why This Company, and Negotiation
  • Situational Questions
  • Company Research
  • Mock Behavioral Rounds
  • Interview Day
  • After the Interview
  • Practice Test: Behavioral and Interview Day
Design a Search Autocomplete System
Course contents

Interview Preparation Bootcamp

Course progress

0%
0 of 177 modules complete
Start Here0/1
  • How to Use This Course
Data Structures & Algorithms0/27
  • Arrays and Hashing
  • Two Pointers
  • Sliding Window
  • Sliding Window: Harder Problems
  • Binary Search
  • Stacks
  • Practice Test: Arrays, Pointers, Windows, Search and Stacks
  • Trees: Traversals and Core Patterns
  • Binary Search Trees and Rebuilding a Tree
  • Tries (Prefix Trees)
  • Heaps and Priority Queues
  • Graphs: BFS and DFS
  • Topological Sort and Cycle Detection
  • Union-Find (Disjoint Set Union)
  • Practice Test: Trees, Heaps and Graphs
  • Dynamic Programming Basics
  • Dynamic Programming: Two Dimensions
  • Dynamic Programming: Hard String Matching
  • Backtracking
  • Backtracking: Constraint Satisfaction
  • Greedy Algorithms
  • Interval Problems
  • Bit Manipulation
  • Math and Geometry
  • String Manipulation
  • Pattern Recall and Mock Coding Rounds
  • Practice Test: DP, Backtracking, Greedy and More

System Design

Foundations0/16
  • The System Design Interview Framework
  • Back-of-the-Envelope Estimation
  • Networking and Protocols for Design
  • API Design and Idempotency
  • Load Balancing, Proxies, and Scaling Out
  • Caching and CDNs
  • Choosing a Database: Storage, Indexes and Transactions
  • Replication, Partitioning, and Sharding
  • CAP, PACELC, and Levels of Consistency
  • Messaging, Queues, and Event-Driven Architecture
  • Distributed Transactions and Data Integrity
  • Coordination, Consensus, and Distributed Locks
  • Reliability, Resilience, and Rate Limiting
  • Observability, Security, and Cost
  • System Design Cheat Sheet
  • Practice Test: System Design Foundations
Case Studies0/23
  • Design a URL Shortener
  • Design a Rate Limiter
  • Design a Notification Service
  • Design a Job Queue System
  • Design a Chat App (WhatsApp)
  • Design an Analytics Pipeline
  • Design a Multi-tenant SaaS Architecture
  • Design a Social Media Feed (Twitter/X)
  • Design a Search Autocomplete System
  • Design a File Storage Service (Dropbox)
  • Design Google Docs
  • Design a Code Review System
  • Design Netflix
  • Design YouTube
  • Design Spotify
  • Design Uber/Lyft
  • Design Airbnb
  • Design Ticketmaster (Eventbrite)
  • Design an E-commerce Cart, Checkout, and Catalog
  • Design a Payment System
  • Design a Logging and Monitoring System
  • Mock Design Rounds
  • Practice Test: System Design Case Studies
Low-Level Design0/19
  • The LLD Interview Framework and UML
  • OOP Foundations for Design
  • SOLID Principles
  • Creational Patterns
  • Structural Patterns
  • Behavioral Patterns I — Strategy, Observer, Command, State, Template Method
  • Behavioral Patterns II and Anti-Patterns
  • Concurrency in Low-Level Design
  • Design a Parking Lot
  • Design an Elevator System
  • Design a Movie Ticket Booking System
  • Design an Expense-Sharing App (Splitwise)
  • Design a Vending Machine and an ATM
  • Design a Rate Limiter and a Logging Framework
  • Design a Notification Service and an In-Memory Cache
  • Design Games — Tic-Tac-Toe, Snake and Ladder, Chess
  • Database Design for LLD
  • LLD Cheat Sheet and Recall Drill
  • Practice Test: Low-Level Design

Backend

Python0/5
  • How Python Runs Your Code
  • Functions Deep Dive: Closures, Generators, Context Managers, Scope
  • Classes Deep Dive: Method Types, MRO, Metaclasses
  • Standard Library and Serialization
  • Practice Test: Python
Django0/6
  • Django Request Lifecycle
  • Lab: Django Middleware — Request ID & Response Time
  • Django ORM and Querysets
  • Django's Cache Framework
  • Practice Test: Django
  • Django in Production: Debugging Labs
FastAPI0/5
  • FastAPI, ASGI, and Async
  • FastAPI Dependency Injection
  • FastAPI Background Tasks
  • Lab: FastAPI Async — Concurrent Aggregation
  • Practice Test: FastAPI
Databases (PostgreSQL)0/6
  • Indexing
  • Query Optimization
  • Transactions and Isolation
  • Migrations and Schema Changes
  • Hierarchical Data and Safe Concurrent Updates
  • Practice Test: Databases
Caching, Queues & Distributed Systems0/8
  • Redis Caching
  • Redis Advanced Patterns
  • Celery and Background Workers
  • Kafka and Message Queues
  • Async Pipelines
  • Distributed Systems Basics
  • Distributed Locks
  • Practice Test: Caching, Queues and Distributed Systems
APIs, Security & Deployment0/9
  • REST API Design
  • API Versioning and Error Handling
  • API Security and Authentication
  • WebSockets and Real-Time Systems
  • Docker and Containers
  • File Storage with S3
  • Testing Strategies
  • Mock Backend Round
  • Practice Test: APIs, Security and Deployment
Frontend0/38
  • HTML Document Structure and Semantics
  • CSS Box Model, Flexbox and Grid
  • CSS Architecture and Theming
  • CSS and Rendering Performance
  • Variables, Scope, Hoisting, and Truthiness
  • Functions, this, and Binding
  • Objects and Prototypal Inheritance
  • JavaScript Utility Patterns: Cloning, Caching, and Memory
  • Promises From Scratch
  • The Event Loop and Browser Rendering Pipeline
  • The DOM: Nodes, Events, and Traversal
  • Practice Test: HTML, CSS and JavaScript
  • React Rendering Fundamentals
  • React Hooks Internals
  • React Performance
  • Lab: React — Stateful Counter Component
  • State Management
  • State Machines in React
  • React Custom Hooks and Composition Patterns
  • TypeScript for React
  • React Testing
  • Practice Test: React
  • HTTP and Caching
  • Network Performance and Web Vitals
  • Code Splitting and Bundles
  • Virtualization
  • GraphQL and Data Fetching
  • Web Security
  • WebSockets and Real-time
  • SSR and Next.js
  • Micro-frontends
  • Build Tools and Bundling
  • Accessibility
  • Error Handling
  • Internationalization
  • Animation
  • Rapid Recall and Mock Frontend Rounds
  • Practice Test: Performance, Architecture and Production
Behavioral & Interview Day0/14
  • Resume and Project Walkthroughs
  • The STAR Method and Refining Your Stories
  • Conflict and Difficult Coworkers
  • Failures, Incidents, and Obstacles
  • Leadership, Mentorship, and Ownership
  • Teamwork, Communication, and Feedback
  • Growth and Handling Ambiguity
  • Career Goals, Why This Company, and Negotiation
  • Situational Questions
  • Company Research
  • Mock Behavioral Rounds
  • Interview Day
  • After the Interview
  • Practice Test: Behavioral and Interview Day
Browsing without an account — progress is saved in this browser only.Sign in to save it

Design a Search Autocomplete System

System Design60 min
Sign in to open the interactive design canvas for this exercise.

Autocomplete (typeahead) shows suggestions as you type, like Google guessing "pizza near me" after you type "piz". It's a favorite interview question because it's small enough to fully design in 45 minutes, yet it touches a real data structure (the trie), a ranking problem, and a hard latency limit: it fires on almost every keystroke, so it has to be fast.

Requirements

Functional requirements

  • As a user types a prefix, return the top-K most relevant completions.
  • Suggestions reflect how popular a query has actually been.
  • Suggestions update as new searches come in; they aren't frozen forever.

Non-functional requirements

  • Latency under 100ms per keystroke, ideally under 50ms. This is a hard UX limit, not a nice-to-have.
  • Very high read volume, since it fires on nearly every keystroke of every active user.
  • Freshness: a trending query should surface within minutes to hours, not wait for a full daily rebuild.
  • Availability over strict consistency: a slightly stale suggestion list beats a slow or failed one.

Remember: autocomplete has to be fast enough that the user never notices it's a network call at all. That single constraint is what rules out "just query the database" as an answer.

Sign in to try this knowledge check.

Estimates

Assume a search product with 500 million searches a day, and each typed query averages about 20 characters, meaning roughly 20 potential autocomplete requests per search.

  • Raw keystroke events: 500M × 20 = 10 billion/day, about 116,000/sec average. Client-side debouncing, only firing after a short pause or every few characters, cuts this 5-10x in practice, still tens of thousands of requests per second.
  • Unique query space: assume 100 million unique query strings, about 20 bytes each, 2 GB of raw text. Small enough to fit an entire trie, or a precomputed top-K table, in memory.
  • Update volume: roughly 500M query events a day need to feed back into rankings, but this can be batched (hourly, say) rather than applied instantly.

The number that matters most: query volume is enormous, but the unique query space is small enough to precompute and hold entirely in memory. That gap between "huge traffic" and "small unique data" is what makes this design possible.

API

GET /autocomplete?prefix=piz&limit=10
  -> { suggestions: ["pizza near me", "pizza hut", "pizza recipe", ...] }

That's essentially the whole external contract. Every bit of complexity lives in how the backend serves this fast and keeps it fresh, which is what the rest of this lesson covers.

Data model

The serving structure is a trie: a tree where each node represents one character, so walking from the root spells out a prefix. Picture climbing a tree letter by letter, "p" then "i" then "z", and each branch you take narrows down to fewer and fewer matching words. Each node also caches its own top-K most frequent completions, so a lookup never has to explore the rest of the tree below it.

TrieNode
  children: map[char]TrieNode
  top_k: [(query_string, frequency)]   -- precomputed, sorted desc, size K (e.g., 10)

The trie is rebuilt from a source-of-truth table that tracks how often each query has actually been searched:

query_frequency
  query_text   TEXT
  count        BIGINT
  last_seen    TIMESTAMPTZ
PRIMARY KEY (query_text)

High-level design

Search logs / query events --> Aggregation job (batch, e.g. hourly Spark/Flink job)
                                     |
                          updates query_frequency counts
                                     |
                          Trie builder job --> builds new trie snapshot
                                     |
                          pushes snapshot to Trie-serving nodes (in-memory, sharded by prefix)
                                     |
Client keystroke --> Autocomplete API --> route to shard owning this prefix --> return top_k
                                        --> (cache hot prefixes in a CDN/edge cache too)

Search activity feeds a batch job that periodically recomputes frequency counts, a separate job builds a fresh trie snapshot from those counts, and that snapshot gets pushed out to the servers actually answering requests. The path a user's keystroke takes is short and entirely in-memory: hit the API, route to the shard that owns this prefix, return the cached top-K.

Deep dives

Why does every trie node precompute its own top-K, instead of ranking at query time?

This is the single most important decision in the whole design. A naive trie lookup walks down to the prefix's node, then explores the entire subtree below it to collect and rank every possible completion. For a short, common prefix like "a" or "th", that subtree can hold millions of words, and ranking all of them at request time blows straight through your latency budget.

The fix: do that ranking once, offline, while building the trie, and cache the answer directly on the node. A query then costs O(prefix length) to walk down to the right node, plus O(1) to return the cached list. No live ranking, no subtree walk, on the request path at all.

Remember: precomputing the top-K per node is what turns "rank millions of completions" into "look up a cached answer." Do the expensive work once, offline, not on every keystroke.

Sign in to try this knowledge check.

How do you rank completions, and keep them fresh without rebuilding everything?

The simplest ranking signal is raw historical frequency. A better one decays frequency over time (score = count * decay(time_since_last_seen)), so a query that was popular a year ago fades out while genuinely trending queries rise quickly. Personalization, boosting a user's own recent searches, is applied as a thin re-ranking step on top of the shared global top-K, not baked into the trie itself, which keeps the trie shareable across every user.

Freshness is solved with two tiers, not one. The main trie snapshot rebuilds on a slower, predictable cadence, say hourly, from batched aggregated counts: cheap and consistent, but not instant. For anything spiking faster than that, like breaking news, maintain a small, separately-updated "hot" structure, a bounded count-min sketch or a simple hash map of trending terms updated in near real time, and merge it into the response at query time as an overlay on top of the trie's cached top-K. This avoids rebuilding a multi-gigabyte trie every time one query spikes, while still surfacing genuinely fast-moving trends within minutes.

How does one server hold a query space that doesn't fit in memory?

The trie needs to live entirely in RAM to hit the latency target, which means it's memory-bound, not disk-bound. Once the full query space is too big for one machine, shard the trie by the first character or two of the prefix, so different servers each hold only a slice of the structure. A request for "piz" routes to whichever shard owns prefixes starting with "p" (or "pi"), and that one shard fully answers it without needing data from anywhere else. Replicate each shard for availability and extra read throughput. When it's time to rebuild, build the new snapshot on a separate builder node and hot-swap it into the serving nodes, the in-memory equivalent of a blue/green deploy, so there's no downtime and no query pays a rebuild cost.

Very short prefixes ("a", "th") are both the highest-traffic case and the least useful one, since the results are too broad to be helpful. Many products simply don't fire autocomplete until the user has typed at least two characters, which also cuts a meaningful amount of load.

Trade-offs and follow-up questions

Choice Benefit Cost
Precomputed top-K per trie node O(prefix length) query latency Rebuild cost when frequencies change; some staleness between rebuilds
Batch (hourly) trie rebuild Simple, consistent, cheap Not truly real-time, fixed by the hot-term overlay
Sharding by prefix Spreads load and memory across nodes A prefix only ever needs one shard, so cross-shard queries are simply never needed
In-memory serving Meets the sub-100ms budget Memory cost scales with the unique query space and must fit per shard
Edge/CDN caching of common prefixes Cuts backend load and latency further Adds a small extra layer of staleness on top of the trie's own

Q: How do you keep the trie fresh without rebuilding it constantly? A: A two-tier approach: a periodic full rebuild (hourly, say) from batched frequency aggregation covers the stable long tail cheaply, plus a lightweight, frequently-updated trending overlay covers anything spiking faster than that cadence. The API merges both at response time.

Q: The trie for the full query space doesn't fit on one machine. What do you do? A: Shard by prefix, first character or first two characters, so each serving node holds only a fraction of the trie. A thin routing layer sends each request to the one shard that can fully answer it.

Q: How would you personalize suggestions per user without breaking the shared trie's precomputation? A: Keep the shared trie's top-K global and un-personalized, since that's what makes the precomputation cheap and reusable across every user. Apply personalization afterward, as a thin re-ranking step that boosts items from a small, per-user cache of recent searches.

Sign in to try this knowledge check.
PreviousDesign a Social Media Feed (Twitter/X)NextDesign a File Storage Service (Dropbox)

Course progress

0%
0 of 177 modules complete

On this page

  • Requirements
  • Estimates
  • API
  • Data model
  • High-level design
  • Deep dives
  • Why does every trie node precompute its own top-K, instead of ranking at query time?
  • How do you rank completions, and keep them fresh without rebuilding everything?
  • How does one server hold a query space that doesn't fit in memory?
  • Trade-offs and follow-up questions