Signals that it’s proximity search
- “Near me”, “nearby”, “within 5 km”
- Sorted by distance or ETA
- Pins inside a map viewport
- Positions updating every few seconds
A latitude index reads a strip across the city
A B-tree sorts one dimension, so a 3 km search reads a band 6 km tall and 40 km wide: 9,600 rows to keep 1,130.
Geohash: read your cell and its 8 neighbours
Nearby points can sit in different cells: the closest restaurant, 700 m east, is in tdr1y, not your tdr1v. Read the 3 × 3 block, then filter by distance.
One index for everything?
Bad: Drivers in PostGIS
250,000 pings a second, each a row version, index entry and WAL.
Good: Two homes
Places in a spatial index; drivers’ latest positions in memory.
Climb the ladder. Static and moving split at rung 4.
Most nearby-places designs stop at the database’s spatial index. Points that move every few seconds need a live index in memory.
500,000 restaurants changing about 60 times a second. Build a custom index?
The answer
No. PostGIS with a GiST index, ST_DWithin and KNN ordering, or Elasticsearch when search needs text. Most nearby-places designs should stop here.
Drivers: latest position in memory, by cell
250,000 pings a second never touch a disk index. Each is one GEOADD to its cell’s Redis set, and a sweeper drops drivers silent for 30 s.
Then match the rider
- Search 1 km, then 2, then 4, for 20 drivers
- Rank those 20 by road ETA
- Claim one atomically, then send the offer
Say it like this
Static or moving? Restaurants go in PostGIS or Elasticsearch. Driver pings go to Redis geo sets by cell, with expiry. Widen the ring, rank by ETA, and claim one driver atomically.