Patterns
Geo and proximity search
Find things near a point: geohash and cells, the candidate query, and why 'nearest' is a product decision.
Proximity search answers “what is near here?” The naive plan, compute distance to every row and sort, dies at a city-sized table. You need an index that throws away far-away rows before you do any real math.
The index
Geohash encodes a lat/long as a string of bits. A shared prefix means “same rough area.” You store the hash on the driver and index it. A query computes the user’s cell and the neighboring cells (eight of them, more at a corner or when the cell is coarse) and does WHERE geohash LIKE prefix or IN the neighbor list. Then you compute true distance (haversine is fine) and keep the closest K.
S2 or H3 cells are the same idea with a more even globe. A quadtree or an R-tree (Postgres GiST, a spatial index in MySQL) is the version you get if you stay inside a relational database. Redis GEO* commands are a geohash sorted set, excellent when the set of online drivers fits in memory.
Pick a cell size from the product. Too coarse and each cell is a hotspot full of candidates. Too fine and you touch dozens of cells to fill a radius. It is normal to query a fine level and expand if you did not find enough results.
Distance is not ETA
The index ranks by straight-line distance or by travel on an uncongested graph if you have one. Riders care about time. Take the top few dozen candidates and ask a routing service, with a short cache keyed by a coarsened origin and destination. Do not call it for every driver.
Writes
Location is a hot, tiny, mostly-latest-value dataset. Update a Redis hash and the geo index. Snapshot to durable storage on a slow cadence if you must reconstruct “who was online.” A row per GPS ping is a time-series product, not a matching product. Say so if someone asks for historical trails, and then talk retention and privacy: you do not need block-level precision stored for a year to match tonight’s rides.
Downtown at 6 pm is one cell and one shard. Split busy cells, or cache the candidate id list for a second so a thousand riders do not each walk the same index.
Further reading
Check yourself
Answer the questions. Multiple choice is scored on this device only.
1. Why query neighboring geohash cells, not only the cell the user is in?
2. Drive-time ETA for every driver in a metro is a bad idea because:
3. How do you ingest location updates without melting the database?