Geosearch does not get hard because of the distance formula. It gets hard when the user keeps moving the map while the densest areas create the sharpest traffic spikes.
The chapter ties together geocells, regional caching, index preparation, request serving, and POI updates into one working architecture where both freshness and update cost matter.
For interviews and architecture discussions, this case is useful because it forces you to explain radius search, hot-zone handling, and where the boundary sits between response speed and result precision.
Geo Cells
The key choice is how to cover a search radius with neighboring cells without exploding the amount of unnecessary lookup work.
Hot Zones
City centers, airports, and stations create local peaks, so caching and partitioning should be designed for skew rather than average traffic.
POI Freshness
Place status, opening hours, and temporary restrictions go stale faster than the geometry itself, which is why metadata updates cannot wait for rare batch jobs.
Regional Cache
Caching close to the user reduces latency, but it has to line up with geographic partitioning and clear degraded modes.
Source
System Design Interview
A classic walkthrough of Proximity Service as a core geosearch pattern in product systems.
Proximity Service answers a simple question: what is nearby for a given point, radius, and set of filters. At scale, the difficulty is less about distance math itself and more about spatial indexing, viewport-driven access patterns, and hotspot behavior in the busiest areas.
Even when places do not move every second, the index still sees write amplification from incremental updates, recut cell coverage, and regional synchronization. That is why large deployments usually rely on geographic partitioning first, then apply ordinary sharding inside each region.
Requirements
On the surface this looks like a simple nearby lookup, but internally it is an interactive radius search with a very tight latency budget. In major cities, a handful of districts can climb into millions of QPS, so the design has to preserve both UI responsiveness and load skew tolerance.
Functional
- As the user moves the map, the system returns the nearest POIs in the current viewport.
- It supports nearby lookup by radius, category, and text query.
- Pagination and result ordering remain stable while the user pans and zooms the map.
- Autocomplete is separated from the API that returns full place details.
- Point status, availability, and temporary restrictions can be updated near real time.
Non-functional
Latency: p95 < 200ms
The map UI should stay responsive during pan/zoom and repeated nearby requests.
Availability: 99.99%
Search should keep working even when part of the index or cache is degraded.
Freshness: minutes, not hours
New, closed, or temporarily unavailable places should reach the results quickly.
Scale: millions of QPS
Geo-distributed traffic arrives with strong regional and time-of-day skew.
High-level architecture
The request path should stay clearly separated from index preparation. Nearby lookup lives on a short user-facing read path, so the serving layer needs an explicit degraded mode whenever cache coverage is weak or the search radius suddenly expands.
Client applications
Map UI, pan/zoom, and nearby lookup
Geo gateway
Authentication, quotas, and regional routing
Serving layer
Index access, filtering, and ranking
Hot cache
Redis/Memcached for popular geocells and categories
Geo index store
S2/H3/Geohash plus category posting lists
POI metadata database
Name, opening hours, rating, and business tags
The request runs in two phases: first candidate retrieval across neighboring cells, then ranking based on distance, relevance, and business signals.
Interactive walkthrough of a nearby request
Change the category and radius, then step through the request path.
Step 1 of 5
Geo gateway: request validation and normalization
The edge service validates the query and sends it to the nearest serving region.
- Checks the API key, quotas, and required parameters.
- Normalizes lat/lng, radius, and client locale.
- Routes the request into the closest proximity region.
{
"lat": 37.7793,
"lng": -122.4192,
"radius_m": 1500,
"category": "cafe",
"region": "us-west-1",
"auth": "ok",
"quota": "ok"
}Choosing a spatial index
There is no universally best structure here. In practice this is an engineering trade-off between cover accuracy, update cost, and the amount of geometric complexity you are willing to carry at scale.
| Approach | Where it helps most | Trade-offs |
|---|---|---|
| Geohash | A quick start and storage in a simple key-value layer | Cell geometry is less uniform, and border artifacts show up more often. |
| S2 | Global maps and clean spherical geometry | It requires a more careful implementation and is harder to debug. |
| H3 | Density analytics, heatmaps, and region-based aggregation | Moving between resolutions needs careful tuning. |
| R-tree/QuadTree | Heavy spatial queries directly inside the database | Updates are more expensive, especially under higher write load. |
API and data model
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 used for incremental reindexing
Reliability and common mistakes
The tricky part of this case is holding together locality, acceptable freshness, and a clear degraded mode when part of the geo index or cache becomes temporarily unavailable.
What helps in production
- Regional partitioning by cell ranges plus replication across zones.
- A two-level cache: edge coverage for hot areas and a service cache inside each region.
- Graceful fallback to a coarser index resolution instead of a full outage.
- Incremental reindexing instead of rebuilding the entire dataset every time.
Common mistakes
- Looking in only one cell and forgetting about neighboring cells at the radius boundary.
- Sorting only by distance and ignoring rating, relevance, or place status.
- Mixing the online serving path with the batch path that prepares the index and metadata.
- Building one global cache without regional partitioning or stampede protection.
- Failing to deduplicate POIs when multiple data providers feed the same area.
Tool
S2 Geometry
A practical toolkit for cell-based spatial indexing on the surface of a sphere.
Related chapters
- Airbnb: geoindex and availability - shows a neighboring geo problem where proximity lookup is combined with calendar availability and regional scaling.
- Uber/Lyft: live location systems - extends the topic with continuous location updates, routing, and much tighter latency constraints.
- Search System: ranking and search pipelines - deepens the candidate retrieval, relevance signal, and large-scale search pipeline parts of this problem.
- CDN: edge caching - explains how edge layers reduce geo API latency and shield regional services from traffic spikes.
