Skip to main content
Proximity Service (Yelp, Nearby)lesson 2 of 4 · 2 min read

The Read Path

Four steps

Four steps make up your read path, and you want to be able to narrate them in order.

Turn the user's position into a cell first. Compute the geohash of their coordinates at a precision whose cell exceeds the search radius: six characters, about 610 metres, for a one kilometre search, and five characters, about 2.4 kilometres, for a five kilometre one.

Store several prefix lengths as separate indexed columns, so you pick a column at query time instead of recomputing anything.

Expand to nine cells second. Their own, plus the eight around it, because somebody 40 metres away across a boundary shares no prefix with them and a single-cell query would silently drop them.

Run it as one clause over nine prefixes, a single index range scan each.

Filter exactly third. Those nine cells give you a superset, because cells are rectangles and your search area is a circle, so measuring true distance to each candidate trims the corners. A few hundred candidates cost microseconds here.

Rank fourth. Distance is rarely the ranking on its own, since real products blend rating, popularity, opening hours and paid placement.

Keep that behind its own interface, because it will change far more often than your index will.

Where the capacity comes from

Put the cache between steps two and three, where all your capacity comes from. A cell's candidate list changes only when a business inside it is created or edited, and at one write a second that is almost never.

Cache the cell against its list of businesses with a long expiry and clear it on write. Most of your searches then never touch the database at all.

the shape of it
User tapslat, lon, 1 kmGeohashez3wr, 6 chars9 cellsself + neighboursRediscell to idsIndex shardon cache missHaversine1,840 to 260Rankdistance + ratingexpand98% hitmisstrue radius
step 1 of 5
Nine cheap cell lookups produce a candidate set that one distance pass turns into an exact answer.

Worked example

A user opens the app in Lisbon and searches 1 km. The service computes geohash ez3wr for their position, looks up that plus its 8 neighbours, and finds all 9 lists warm in Redis, an in-memory store, returning 1,840 business ids in 3 ms. It hydrates those from the business cache, runs Haversine against each, and 1,840 candidates become 260 within 1 km. Ranking blends distance with rating and returns the top 20. Total server time 14 ms against a 50 ms budget, and the database was never touched. On a cold cell the same query costs about 40 ms and warms the entry for everyone behind it, which is why hit rates on this cache sit above 98 percent in practice.