System Design

Design Proximity Service

Nearby restaurants/places — geohash indexing, radius search, and ranking by distance + quality.

Interview tip Like Yelp nearby: GEORADIUS on Redis Geo or S2 cells. Clarify update frequency of business hours and duplicate listing merge.

① Functional requirements

  • Search POIs within radius of point
  • Filter by category, price, open_now
  • Sort by distance, rating, or blended score
  • Get POI details (hours, photos, reviews link)
  • Business owner update listing
  • Report closed or incorrect listing

② Non-functional requirements

  • Search p99 < 100ms
  • 50M POIs indexed
  • 20K nearby QPS
  • Index updates within 5 minutes
  • 99.9% availability

③ Back-of-the-envelope scale

Assumptions
  • 50M POIs × 200 bytes geo index ≈ 10GB geo index
  • 20K QPS → Redis cluster or partitioned cell index
  • Top 20 results per query — early terminate radius expansion
  • Updates 1K/sec peak (hours changes)

④ High-level architecture

Proximity Service
Client apps
Nearby API
Geo index (Redis Geo / S2)
POI metadata DB
Ranking service
Geo index returns candidate IDs in radius. Fetch metadata batch from DB/cache. Ranker applies distance + rating + open_now boost.

⑤ Data flow & execution path

Nearby search
① lat,lng,radius② Geo index query③ Fetch POI batch④ Rank + filter⑤ Return top 20
Geohash cell covers query circle
Expand cells if <20 results
open_now from precomputed bitmap per cell
Cache popular downtown queries
Contrast with Uber live driver positions — POIs are mostly static; index rebuild batch vs streaming updates.

⑥ API & interfaces

Endpoint / flowPurposeNotes
GET /nearbyRadius searchlat,lng,radius,category
GET /poi/{id}POI detailscacheable
PUT /poi/{id}Owner updateauth required
POST /poiAdd listingmoderation queue

⑦ Data model & storage

POI: id, lat, lng, categories[], rating, hours_bitmap, geohash. Geo index: geohash → poi_ids[] or Redis GEOADD.
StoreWhatWhy
Redis GeoLive geo indexGEORADIUS
PostgreSQLPOI metadataACID updates
CDNPhotosStatic assets

⑧ Deep dive — core components

Geohash cell expansion

Start with cell containing point. If results <20, query neighbor cells ring until radius covered or cap cells. Avoid full table scan.

open_now filter

Precompute open bitmap per POI for next 7 days in local TZ. At query, bitwise check — filter before rank to shrink candidate set.

⑨ Trade-offs & alternatives

DecisionOption AOption BPick when
IndexRedis GeoS2 cellsRedis ops-simple; S2 better at poles/spans
RankDistance onlyML rankerDistance cheap; ML for engagement
UpdatesRealtime indexBatch nightlyBatch OK for static POIs
CacheQuery cacheNo cacheCache downtown lat/lng grids

⑩ 45-minute interview script

  1. 0–5 min: Nearby + filters
  2. 5–10 min: POI scale
  3. 10–20 min: Geo index query
  4. 20–30 min: Ranking + open_now
  5. 30–38 min: Updates + moderation

⑪ Likely follow-up questions

QuestionShort answer
Multi-radius pagination?Cursor with last distance + id; expand radius if page empty
Chain duplicate merge?Canonical chain_id groups franchises; dedupe in ranker
Ads in results?Reserve slots 3,7; blend sponsored score with relevance cap

⑫ Revision checklist

  • GEORADIUS / S2
  • Cell expansion algorithm
  • Batch metadata fetch
  • Distance + rating rank
  • open_now precompute
  • Query result cache
  • Owner update path
  • Moderation for new POI
proximitygeospatialyelpgeohashnearby