What an interviewer expects you to nail down before drawing a single box.
GET /v1/search?lat={}&lng={}&radius={} → { businesses: [...] }GET /v1/businesses/{id} → { business }PUT /v1/businesses/{id} { hours, phone, ... } → { status }POST /v1/businesses/{id}/reviews { rating, text } → { review_id }You are standing on a corner in a new city, you type 'coffee' into Yelp, and a ranked list of nearby cafes appears almost instantly. The interesting question is how the system finds the handful of relevant businesses out of millions, sorted by distance from exactly where you are standing, fast enough that it feels immediate. The answer is a geohash index plus two layers of caching.
The design splits into two read paths and one write path. The Location-Based Service handles 'what is near me' and never writes anything. The Business Service handles a business's detail page and the edits an owner makes to their own listing. Keeping the read-heavy nearby search apart from the write-light owner updates lets each scale on its own.
Here is the nearby flow in plain steps. Your phone sends its lat/lng and radius to the Location-Based Service. From the radius it picks a geohash length (a longer hash means a smaller cell), computes the geohash for your location, and also takes the eight neighboring cells, because the place you want might sit just across a cell boundary. For each of those cells it asks the geohash cache for the list of business IDs in that cell. Then it looks up each business object in the business-info cache, computes the exact distance, keeps the ones truly inside your radius, ranks them, and returns the list.
Why two caches? One maps a geohash cell to the business IDs inside it, which is the expensive geo lookup. The other maps a business ID to its full object (name, hours, rating), which is what you actually render. Splitting them means a hot area's cell lists stay cached even as individual business objects are fetched and updated independently. The geohash index table in the database is the source of truth behind the cell cache; because the whole index fits in memory, it is scaled with read replicas rather than sharding.
Geohash cells are squares but a radius is a circle, so the corners do not line up. The fix is to overscan and then filter, like grabbing every book on a shelf whose edge touches the area you care about and then setting aside the few just past your reach. Owner edits do not need to be instant, so a business update is effective the next day after a job refreshes the business-info cache. This system teaches geohashing and neighbor cells for nearby search, the two-cache design, separating read-heavy search from write-light edits, and matching each store to its data's write pattern.