Source
System Design Interview
Classic Proximity Service as a separate geosearch pattern in product systems.
Proximity Service is a service that answers the question: “what is nearby” for a given point, radius and filters. In a Google Maps-level product, the architecture is built around two different contours: offline ingestion/indexing And online low-latency serving.
Requirements
Functional
- The user moves the map and gets the nearest POI in the current viewport.
- Search nearby by radius, category and text query.
- Support for pagination and stable order of results when scrolling the map.
- Separate API for tooltips (autocomplete) and API for point details.
- Online update of data on the load/status of the point (optional).
Non-functional
Latency: p95 < 200ms
The map UI should not lag when pan/zooming.
Availability: 99.99%
Search should work even if some of the indexes are degraded.
Freshness: minutes, not hours
New/closed points should appear in the search results quickly.
Scale: millions of QPS
Geo-distributed traffic with clearly defined hot zones.
High-Level Architecture
Client Apps
Map UI, pan/zoom, nearby search
Geo API Gateway
Auth, throttling, routing by region
Proximity Serving
Geo index lookup + ranking + filters
Hot Cache
Redis/Memcached, geocells of popular zones
Geo Index Store
S2/H3/Geohash + posting lists by category
POI Metadata DB
Name, opening hours, rating, tags
The request is processed in two phases: candidate retrieval across adjacent cells, then ranking taking into account distance, relevance and business signals.
Interactive processing of a nearby request
Change the category and radius, then go through the pipeline step by step.
Step 1 from 5
Geo API Gateway: query validation and normalization
The service validates the input parameters and sends the request to the nearest region.
- Checking the API key, limits and required parameters.
- Normalization of lat/lng, radius and client locale.
- Route-by-region to the nearest proximity serving cluster.
{
"lat": 37.7793,
"lng": -122.4192,
"radius_m": 1500,
"category": "cafe",
"region": "us-west-1",
"auth": "ok",
"quota": "ok"
}Selecting a spatial index
| Approach | Where is it especially useful? | Compromises |
|---|---|---|
| Geohash | Easy start and key-value storage | Unevenness of cells and edge effects near borders. |
| S2 | Global maps and neat sphere geometry | Implementation and debugging are more difficult. |
| H3 | Analytics, densities, heatmaps | Transitioning between resolutions requires careful setup. |
| R-tree/QuadTree | Heavy spatial queries in the database | More expensive to update under high write load. |
API and data model (simplified)
Main API
GET /v1/places/nearby?lat=37.78&lng=-122.41&radius=1500&category=cafe&limit=20
Response:
{
"items": [
{ "place_id": "p123", "distance_m": 120, "score": 0.91 },
{ "place_id": "p889", "distance_m": 240, "score": 0.88 }
],
"next_page_token": "..."
}Index and metadata
- geo_cell_index: cell_id -> place_ids
- poi: place_id, name, category, coords, rating, business_hours
- popularity_signals: recent clicks/check-ins/reviews
- change_log: events for incremental re-index
Reliability and anti-patterns
What helps in production
- Regional sharding by cell ranges + replication by zones.
- Two-level cache: edge cache for popular zones + service cache.
- Graceful degradation: fallback to a coarser index resolution.
- Incremental reindex instead of a full index recalculation.
Common mistakes
- Search only in one cell and forget about neighboring cells on the border of the radius.
- Sort only by distance without quality score (rating, relevance, open/closed).
- Do not separate the online serving index from the data preparation batch pipeline.
- Make a global cache without regional sharding and without stampede protection.
- Forget about deduplicating POIs from different data providers.
Reference
S2 Geometry
A practical tool for cell-based spatial indexing on a sphere.
