When an interviewer asks you to design a proximity service such as Yelp, they are looking for how you translate a user‑facing product into a set of scalable components. The conversation usually starts with a high‑level description, then narrows down to the hardest parts – real‑time geo queries, data freshness, and fault tolerance. Below is a walkthrough you can follow in a typical 45‑minute interview.
1. Clarify the Scope and Requirements
Begin by asking clarifying questions. This shows you care about the product and helps keep the discussion focused.
- Core functionality: Users search for businesses (restaurants, shops, etc.) near a latitude/longitude pair and filter by category, rating, price, or opening hours.
- Key operations:
SearchNearby(lat, lon, radius, filters)→ list of businesses.AddBusiness(businessInfo)→ create.UpdateBusiness(id, updates)→ edit.WriteReview(businessId, review)→ add rating/comments.
- Non‑functional goals:
- Low latency: < 200 ms for a typical search.
- High availability: 99.9 %+ uptime, graceful degradation.
- Scalability: Handle spikes (e.g., holiday weekend) without a major performance hit.
- Data freshness: Updates (new business, rating changes) should be visible within a few seconds.
- Assumptions: Global coverage, read‑heavy workload, occasional write bursts. Mobile and web clients are out of scope for the design.
2. Identify Core Entities and Data Model
| Entity | Primary Fields | Important Indexes |
|---|---|---|
| Business | id, name, category, location (lat,lon), rating, price_range, open_hours | Geo‑index on location, composite index on category+rating |
| Review | id, business_id, user_id, rating, text, timestamp | Index on business_id |
| User (optional) | id, name, email | Primary key |
The location field is the linchpin for proximity queries, so it must be stored in a structure that supports fast radius searches.
3. Sketch a High‑Level Architecture
+----------------+ +----------------+ +-------------------+
| API Gateway | ---> | Service Layer | ---> | Geo Index Store |
+----------------+ +----------------+ +-------------------+
| | |
v v v
+----------------+ +----------------+ +-------------------+
| Auth Service | | Business Svc | | Review Service |
+----------------+ +----------------+ +-------------------+
| | |
v v v
+----------------+ +----------------+ +-------------------+
| Cache (CDN) | | DB (SQL) | | DB (SQL) |
+----------------+ +----------------+ +-------------------+
- API Gateway: Handles request routing, rate‑limiting, and basic auth.
- Service Layer: Stateless microservices (
BusinessService,ReviewService,SearchService). - Geo Index Store: A dedicated datastore (e.g., Elasticsearch, OpenSearch, or a purpose‑built quad‑tree) that supports
geo_distancequeries. - Cache: Frequently accessed search results or hot business profiles cached in Redis or an edge CDN.
- Primary DB: Relational store for strong consistency on business and review data.
4. Deep Dive: Geo‑Based Search
4.1 Choosing the Right Index
- R‑tree / Quad‑tree: Good for in‑memory, low‑latency lookups but harder to scale horizontally.
- Geohash + B‑tree: Encode lat/lon into a string; range queries become prefix scans. Works well with distributed KV stores.
- Elasticsearch: Provides built‑in
geo_pointandgeo_distancequeries, automatic sharding, and replication.
In an interview, mention that you would start with Elasticsearch for its out‑of‑the‑box capabilities and later consider a custom geo‑hash solution if cost or latency becomes a concern.
4.2 Query Flow
- Client sends
GET /search?lat=…&lon=…&radius=5000&category=restaurant. - API Gateway validates auth and forwards to
SearchService. - SearchService checks the cache. If a miss, it builds a geo‑distance query and sends it to the Geo Index Store.
- Geo Index Store returns a list of business IDs sorted by distance.
- SearchService fetches the full business records from the primary DB (or a read‑replica) and enriches them with rating aggregates.
- Result is cached for a short TTL (e.g., 30 seconds) and returned to the client.
4.3 Handling Data Freshness
- Write Path: When a new business is added, the
BusinessServicewrites to the primary DB and simultaneously updates the Geo Index Store via an async message (Kafka). - Eventual Consistency: The index may lag by a few seconds, which is acceptable for most user experiences. If stricter freshness is required, the service can perform a direct DB lookup for recent writes.
5. Scaling the System
- Read‑Heavy Load: Deploy multiple
SearchServiceinstances behind a load balancer. Use read replicas for the primary DB to spread the query load. - Sharding: Geo Index Store shards by geohash prefix, ensuring queries hit only relevant shards.
- Cache Warm‑up: Pre‑populate cache for popular locations (city centers) during off‑peak hours.
- Back‑pressure: Use circuit breakers to protect downstream services when latency spikes.
6. Trade‑offs and Alternatives
| Concern | Approach | Trade‑off |
|---|---|---|
| Latency | In‑memory quad‑tree | Faster reads, limited horizontal scaling |
| Consistency | Write‑through to DB + async index update | Slight staleness in search results |
| Cost | Managed Elasticsearch service | Higher operational cost vs. self‑hosted KV + geohash |
| Flexibility | Separate microservices | More operational overhead, but easier to evolve each domain |
Discuss why you might pick one over the other based on the product’s SLAs and budget.
7. Typical Follow‑Up Questions
- How would you handle “search near me” with a moving user – talk about continuous location updates, caching per session, and short TTLs.
- What if the service must support ranking by relevance (e.g., rating + distance) – introduce a scoring function that combines normalized distance and rating, possibly using Elasticsearch’s function score.
- How to prevent hot‑spot overload in a popular city – implement request throttling per IP, use geo‑partitioned caches, and consider a read‑only replica for that region.
- How to store and query opening hours efficiently – store as a bitmask per day, enable range queries for “open now”.
- How to ensure data privacy for user‑generated reviews – encrypt sensitive fields, apply access controls, and purge data on request.
8. Sample Answer Snippet (45‑90 seconds)
"For a Yelp‑style proximity service, I’d start by defining the core APIs: a
SearchNearbyendpoint that takes latitude, longitude, radius, and optional filters, plus CRUD operations for businesses and reviews. The biggest technical challenge is the geo‑search, so I’d use Elasticsearch’sgeo_pointtype to index business locations. When a user searches, the request hits an API gateway, which forwards to a statelessSearchService. The service first checks a Redis cache; on a miss it queries Elasticsearch for IDs within the radius, then fetches the full business records from a read‑replica of our relational DB. Writes go to the DB and are streamed via Kafka to update the Elasticsearch index asynchronously, giving us sub‑second freshness. To meet low‑latency goals, I’d shard the index by geohash prefix and place read replicas close to the users. For availability, we’d run multiple service instances behind a load balancer and use circuit breakers to protect downstream components. Trade‑offs include accepting slight index lag for faster writes, and higher operational cost if we use a managed Elasticsearch service versus a custom geo‑hash solution."
9. How to Practice This
- Mock the interview: Use a timer and walk through the steps aloud, as if you were explaining to a colleague. Record yourself to catch filler words.
- Build a mini prototype: Implement a simple
SearchNearbyusing a geohash library and a small dataset. Observe latency and experiment with caching. - Review follow‑up questions: Write bullet‑point answers for the typical follow‑ups listed above. Practice switching between high‑level design and deep dives without losing context.
Tip: When rehearsing, let Call Assistant listen to your answer. It can surface a concise version grounded in your résumé and keep the conversation on track, helping you refine the narrative before the real interview.
Frequently asked questions
What is the best way to store geographic coordinates for fast radius searches?
Use a datastore that supports geo‑point indexing, such as Elasticsearch or a geohash‑based key‑value store. These allow efficient `geo_distance` queries and can be sharded by location.
How do I keep the search index up to date without hurting write latency?
Write to the primary relational database first, then publish an event to a message queue (e.g., Kafka). A background consumer updates the geo index asynchronously, giving near‑real‑time freshness while keeping the write path fast.
What are common trade‑offs between consistency and latency in a proximity service?
If you require strong consistency, every write must synchronously update the search index, increasing latency. Accepting eventual consistency lets you batch index updates, reducing latency but allowing a brief window where recent changes aren’t searchable.
How can I handle spikes in traffic for a popular city center?
Deploy read‑replicas and cache hot results with short TTLs. Use geo‑partitioned caches and rate‑limit per IP or session to prevent overload, and consider a fallback to a simplified search that only uses the DB if the index is saturated.
#system design#proximity service#geo indexing#scalability#interview prep#a proximity service like Yelp