Design a proximity service (Yelp)
Design the "nearby" search of an app like Yelp: given a user's location and a radius, return the businesses around them. Business owners can add, update or delete their business.
Practise it in the interview simulatorDraw your design on a canvas, stress test it with real traffic, and get a scored report. Or watch this answer build itself, step by step.1. Clarify the requirements
Before drawing anything, ask questions. These are the answers an interviewer would typically give:
- How many users and businesses?
- 100 million daily active users and 200 million businesses.
- Search radius?
- Users pick 0.5, 1, 2, 5 or 20 km. Default 5 km.
- Do owner updates need to show at once?
- No: a change can appear the next day.
- Searches per user?
- About 5 a day.
- Moving users?
- Assume the user stands still during a search; the app re-searches when they move far.
- Latency?
- Results should appear in well under a second.
2. Estimate the scale
Assumptions: 100M DAU, 5 searches each a day, 200M businesses, ~1 KB of data per business.
- Search QPS: about 5800 searches/s100M × 5 ÷ 86,400 ≈ 5,800 searches/s.
- Peak search QPS: about 17K searches/sPeak ≈ 3 × average ≈ 17,000/s (lunch and dinner).
- Business data: about 200 GB200M × 1 KB = 200 GB: fits on one database server, so scale reads with replicas.
3. The high-level design
- Two services behind one load balancerSearches (huge volume, read-only) and owner edits (tiny volume) go to different services, so each scales on its own.
- A geospatial indexGeohash turns a location into a short string; nearby places share a prefix. A table of (geohash, business_id) answers 'what's in these cells' in milliseconds.
- Cache the cellsThe same cells are searched over and over: cache geohash → business IDs for each precision.
- Business detailsNames, hours and photos live in a regular database read by ID (cached). 200 GB fits one primary, so replicas carry the reads.
- Watch it in productionMetrics and alerts close the loop: search p99, cache hit ratio and replica lag.
4. The components and what each one does
- Load balancer Load balancer
- Routes /search/nearby to the location-based service and /businesses to the business service.
- Location-based service Service
- Read-only and stateless: compute the user's geohash, read that cell and its 8 neighbours, rank by distance.
- Business service Service
- Owners add, update and delete businesses; changes show up the next day.
- Geospatial index SQL database
- (geohash, business_id) rows; read replicas serve searches, with failover. Small enough not to shard; shard by region if it grows.
- Geohash cache Cache · Redis
- geohash → business IDs, per precision. Rebuilt nightly.
- Business cache Cache
- business ID → details.
- Business DB SQL database
- Primary for owner edits; read replicas for searches; replicated per region.
- Metrics & alerts Metrics & alerts
- Dashboards and alerts on p99 latency, error rate, queue depth and cache hit ratio, so a bottleneck shows up before it becomes an outage.
5. Deep dive: indexing locations
How do you find businesses near a point quickly? Compare geohash, quadtree and S2, and handle a search right on the edge of a cell.
- Geohash turns latitude/longitude into a string; places close together share a prefix. Precision 6 ≈ 1.2 km × 0.6 km cells.
- Search the user's cell and its 8 neighbours, so businesses just over a boundary aren't missed.
- A quadtree is an in-memory tree that splits dense areas; it's fast but takes time to rebuild, so update it incrementally or nightly.
6. What interviewers listen for
- Search API with location and radiusGET /v1/search/nearby?latitude=…&longitude=…&radius=…, paginated.
- Geohash, quadtree or S2Name the index and how it maps a location to nearby candidates.
- Search neighbouring cells too (the boundary problem)Two places can be metres apart but in different cells: always include the 8 neighbours.
- Read replicas and cached cells for a read-heavy loadSearches outnumber edits 100 to 1: replicate and cache what searches read.
- Owner changes applied in batches (next day is fine)Since changes may show the next day, rebuild indexes and caches in batches.
- Database replication and failoverA single database is a single point of failure. Replicas give redundancy and read capacity; failover promotes a replica when the primary dies.
- Partition (shard) data as it growsOne machine eventually can't hold the data or the write load. Say how you'd split it and by which key.
7. Follow-up questions
- A user stands right on the border of a geohash cell, and the restaurant 50 m away doesn't show up. Why, and what's the fix?
- Times Square has 50,000 businesses in one small cell, and a rural cell has none. How does your index cope with both?
- An owner changes their opening hours. When do users see it, and how?
The key points for each follow-up, your scored report and the stress test are part of Pro: ₹299 a month or ₹1,999 a year.
See ProThe design in a nutshell
- Load balancer routes /search/nearby to the location-based service (stateless, read-only) and /businesses to the business service.
- Geospatial index: geohash (or quadtree) → business IDs, kept in a cache cluster and a geo table with read replicas.
- Search: compute the user's geohash at the right precision, read that cell + 8 neighbours, rank by distance, hydrate details from the business cache/DB.
- Owner edits go to the business DB (primary); indexes and caches are refreshed nightly; replicate per region for latency and availability.
Related lessons: Geohash: turning a location into a string · Quadtree: split where the businesses are · Searching, step by step