Location & logistics
Proximity search - the index is the design
Teaches how to size a geospatial index against the query it serves, and why the nearest answer is usually in the cell next door.
What this board gets wrong on purpose
The tension
The board picks one cell size - geohash length 6, about 1.2 km by 0.6 km - and a fixed nine-cell fan-out, which is the correct trade only for a search radius near 1 km in a city of average density. In Manhattan those nine cells hold 4,000 candidate places and the exact distance filter throws away 97% of what it fetched; in rural Montana they hold two, so the query widens to length 4 and now scans an area 30 km across to find anything at all. The board handles that by switching index, which means there are two indexes to keep consistent and a discontinuity in result quality exactly at the boundary between them. A true answer - S2 or an adaptive quadtree that splits on density, so a cell holds a roughly constant NUMBER of places rather than a constant AREA - is deliberately not drawn here, because it replaces a lookup you can compute in the client with a tree you must traverse on the server. Geohash cells are also not square and get narrower towards the poles, so the nine-cell neighbourhood covers a different real area in Oslo than in Nairobi, and nothing on this board corrects for it.
1 · Requirements
Fifty million places that barely move, and twenty-five million searches a day that all ask the same question from a different point. Everything below is downstream of one decision: how big is a cell.
Ask these before designing
- What is the query radius, and is it fixed? The whole index is sized against it. "Within 1 km" and "the 20 nearest" are different systems: the first is a bounded area, the second is an unbounded expansion that stops when it has enough.
- Is "near" the ranking, or a filter before the ranking? If results are ranked by rating and distance is a filter, the index returns a set. If they are ranked by distance, the index must return them in order, and that changes whether a cell scan is enough.
- How stale may a place be? A restaurant that closed last month still being returned is a product bug, not an index bug, but it decides whether the index can be rebuilt nightly or must be written synchronously.
- Do we need polygons, or only points? "Within 2 km of me" is a point query. "Inside this delivery zone" is a polygon containment test, which geohash cannot do and PostGIS can. Answering the wrong one of these is how a geohash index ends up with a PostGIS instance bolted to its side.
- What fraction of searches are in the ten densest cells? If it is most of them, a constant-area grid is the wrong shape and the honest answer is an adaptive tree.
- Is the searcher’s own position accurate? A 50 m GPS error and a 1 km radius are fine together. A 50 m error and a "what is in this building" query is not a search problem at all.
Functional
- Given a point and a radius, return the places within it, ranked.
- Filter by category, open-now and rating, applied after the geometry rather than before it.
- Widen automatically when a cell neighbourhood is too sparse to fill a page of results.
- Owners create, move and close places; the index reflects a change within a minute.
- Serve the exact-distance number, not just the ordering, because the UI shows "420 m".
Non-functional
- Search p99 under 120 ms server-side, of which the index lookup is under 15 ms and the rest is ranking and hydration.
- Recall of the true nearest 20 must be 100% within the stated radius. This is what the 9-cell fan-out buys, and it is a correctness requirement: a proximity search that silently misses the closest result looks perfect in a demo.
- Read-dominated by four orders of magnitude - see the capacity page. Design for reads and let writes be slow.
- Availability 99.99% for search, degrading to a cached and slightly stale result set rather than an error.
- Cell ids are computed on the client as well as the server, so the encoding must be a pure function with no service call in it.
Explicitly out of scope
Routing and travel time (that is the routing board), continuous tracking of the searcher, polygon containment and enter/exit events (that is the geofencing board), personalised ranking and ads.
The rest of this board
Available on Tier Slate
This page publishes the question. The answer — 5 more written pages, an 8-step narrated walkthrough and a 5-table schema — is the board itself, and it opens in Tierslate.
- 5written pages
- 8walkthrough steps
- 5tables34 columns
5 pages behind this one
- Capacity estimation
- Storage estimation
- Availability
- How it works
- Deployment plan
More boards
Geospatial indexes, matching and moving things.