Design a Proximity Service (Yelp)
Proximity search finds places near a point on a map. A proximity service answers those searches within a stated radius and ranks the results by distance.
The ask
A proximity service answers one core question. Which places sit near this point?
The asker gives a point on the map and a radius. The radius is the search distance, set at 5 km in this design.
Results show the place name, its distance and a few facts like rating and opening hours. A search can also filter by category, like food or fuel.
Place owners add and update their places. Directions and booking sit outside the service.
Estimate the scale
The store holds 200,000,000 places. Each place is a small record, and the hard part is finding the near ones fast.
Searches reach 100,000,000 a day.
100,000,000 searches / 86,400 seconds = about 1,157 searches per second.
Place updates reach 1,000,000 a day.
1,000,000 updates / 86,400 seconds = about 12 updates per second.
Reads outnumber writes by a wide margin. The design spends its effort on the read path.
API and data
The search operation takes a latitude, a longitude, a radius and a category. Latitude and longitude are the two numbers that pin a point on the map.
The search returns one page of place summaries. Each summary carries the place name, its distance and its rating.
A place record holds an ID, a name and a location. It also holds a category, opening hours and a rating.
A second operation fetches one place in full. It returns photos, reviews and contact details for that place.
Owners write through an update operation. The update names the place and the fields that changed.
Results come in pages. A page holds a small set of summaries, and a marker fetches the next page.
High-level design
A search service takes each search and runs it against a geospatial index. A geospatial index organises places by location, so near places sit near each other in the index.
The place store holds the full records. The index holds locations and place IDs only.
A cache holds the answers to popular searches. A busy corner asks the same search many times a minute.
Owner updates flow into the store, then into the index. A changed place also clears cached answers that cover its area.
Search traffic splits by area. Each index shard holds the cells for its part of the map.
How a search runs
The point falls inside one small map cell. The index divides the map into cells, and each cell lists the places inside it.
The search reads the point's cell and the cells around it. Together they cover the whole 5 km circle.
Each candidate place gets an exact distance check. Places outside the radius drop out.
The survivors sort by distance, nearest first. The first page goes back to the asker.
Deep dive: cells and boundaries
A geohash names a cell as a short code. Nearby points share the start of their codes, so one prefix finds one area.
A quadtree splits a busy area into smaller cells. Quiet areas keep large cells.
Small cells hold few places, so checks stay cheap. Large cells return many candidates that the distance check then rejects.
The boundary is the trap. A place just across a cell edge can sit metres from the point. The search always reads the ring of neighbour cells for that reason.
A dense centre holds far more places per cell than open country. Cell size follows density, not a fixed grid alone.
Deep dive: keeping places fresh
A place closes, moves or changes its hours. A stale answer sends a person to a shut door.
Owner updates reach the index within seconds. The update path writes the store and the index together, or the index rebuilds the changed cell.
Cached answers carry a short expiry. An update to a place clears the cached searches for its cells at once.
Ratings change slowly and can lag. Distance and location cannot lag, so they take the fast path.
Ordering the results
Distance orders the results first. Two places at the same distance order by rating.
Open now is a strong filter. A closed place at the top of the list helps nobody.
Popularity can lift a result a little. It never lifts a far place over a near one, or the search stops meaning near.
Evaluation and trade-offs
Cell size trades index size against wasted distance checks. The right size differs between a city centre and open country.
The cache trades freshness for speed. Short expiries and update-driven clearing keep that trade safe.
Exact distances cost more than cell checks. The design pays that cost only for candidates inside the covering cells.
A search point is location data about a person. The service keeps it only as long as the search needs it.
The proximity service in numbers
| Item | Figure |
|---|---|
| Places stored | 200,000,000 |
| Searches a day | 100,000,000 |
| Searches a second | 1,157 |
| Search radius | 5 km |
| Place updates a day | 1,000,000 |
| Updates a second | 12 |
Exercise
Why does a proximity search read the cells around the point's cell as well?