Learning pathsA
GUIDED PRACTICE

Review: Yelp

Design nearby business search with text, category, and geographic filters.

Interview scope and guarantees

Find nearby businesses, filter by category, retrieve details, and submit reviews. Define radius, ranking and result freshness. A location candidate is not necessarily inside the radius; final geometry must be checked. Review editing and business ownership are separate authorization paths.

Capacity worksheet

Assume 10 million searches/day: 116/s average and 1,157/s at 10× peak. With 1,000 candidate businesses per query, that peak already evaluates about 1.16 million candidate distances/s. Density, not just total business count, determines query cost.

Concrete API contract

Contract / pseudocode
GET /businesses?lat=...&lon=...&radius=...&category=...&cursor=...
GET /businesses/{id}
POST /businesses/{id}/reviews {rating,text}
PUT /reviews/{id} {expectedVersion,rating,text}

Data model and access paths

Contract / pseudocode
businesses(id PK,position,category,status,version)
reviews(id PK,business_id,user_id,rating,version)
geo_entries(cell_id,business_id,position)
rating_totals(business_id,sum,count,projection_version)
business_categories(business_id,category_id); PK(business_id,category_id)
opening_intervals(business_id,time_zone,weekday,start_local,end_local)
exceptional_hours(business_id,date,intervals)

Evolve a solution and explain each change

Three architecture decisions for Yelp, including the pressure each introduces.
Scroll to inspect the diagram, or open it at full size.

Figure — Three architecture decisions for Yelp, including the pressure each introduces.

Step 1: Filter nearby records

Store businesses and query a coarse spatial region. A rectangular or cell candidate region includes false positives.

Step 2: Refine distance and filters

Check exact distance, category, hours, and query semantics before ranking. A cell boundary can hide a closer business unless neighbors are considered.

Step 3: Scale the search projection

Use an indexed read model and caches with an explicit freshness policy. Ranking caches can preserve closed or removed businesses.

Responsibility overview

Connected responsibilities for Yelp. Trace the authoritative and derived paths separately.
Scroll to inspect the diagram, or open it at full size.

Figure — Connected responsibilities for Yelp. Trace the authoritative and derived paths separately.

Worked end-to-end scenario

A user searches for open cafés within three kilometres near the edge of a spatial cell. Candidate discovery includes the intersecting neighboring cells, not just the containing cell. Exact distance then removes businesses outside the radius. Opening-hours filtering uses the business timezone and exceptions, not the user device timezone. Rank the survivors using a defined combination of distance and relevance. A newly closed café can remain in a stale index; decide whether the detail page rechecks authoritative availability or whether a bounded delay is acceptable. Separate the search result’s approximate ranking from facts users rely on when travelling.

Why these access paths matter

Businesses have stable IDs and coordinates; index spatial cells plus category/status filters. Reviews are stored separately with business and author access paths. Cache by normalized search region and filters, with care for time-dependent open-now results. Pagination needs a deterministic tie-breaker and preferably a snapshot for changing scores.

Build the baseline first

Yelp: baseline request paths.
Scroll to inspect the diagram, or open it at full size.
  1. Search → intersecting cells → candidate businesses.
  2. Exact distance and filters → ranking → page.
  3. Review write → durable record → rating projection.

Evolve the design under load

Yelp: additional scaling and recovery paths.
Scroll to inspect the diagram, or open it at full size.
  1. Dense cells → finer resolution or spatial tree.
  2. Hot-area candidate cache → current status checks.
  3. Search replicas → bounded result candidates.

Defend the hardest decision

A geohash or grid is a candidate retrieval mechanism. Enumerate all cells intersecting the search circle, deduplicate businesses, calculate exact distance, then filter. Searching only the user’s cell misses a nearby business across a boundary. A nearest-K query may need progressive radius expansion with a stopping condition; stopping after the first nonempty cell is incorrect.

Failure and recovery analysis

A business closes but remains in the index. Versioned updates and tombstones prevent stale replays from restoring it; current status filtering protects responses during index lag. Rating edits must apply the difference between old and new contributions rather than increment count each time. Snapshot pagination prevents changing scores from causing excessive duplicates.

Security and privacy boundary

Protect reviewer identity where required, authorize business edits, and reject abusive review automation.

Interview follow-ups with reasoning

Question: How do you handle dense downtown areas?

Show answer and explanation

Answer: Refine cells and cap candidates while preserving the documented ranking contract.

Question: How do you update an address?

Show answer and explanation

Answer: Remove the old cell membership and add the new version idempotently.

Question: What if the geospatial index is lost?

Show answer and explanation

Answer: Rebuild it from authoritative coordinates.

Operate and verify the design

Candidate count, exact-distance cost, index lag and stale-business filtering.

Move a business across a cell boundary while queries run and verify no permanent duplicate or omission.

A second scenario to test transfer

A user stands ten meters west of a cell boundary. The nearest cafe is twenty meters east of that boundary. Searching only the user’s cell misses it even though another cafe in the same cell is a kilometer away. Query neighboring intersecting cells, then reject points outside the actual circular radius. The grid reduces work; exact filtering preserves the query’s meaning.

What evidence would show that the search index is causing poor nearby results?

Show answer and explanation

Answer: Measure candidate recall near cell boundaries, exact-filter rejection rate, index lag, empty-result rate, and query latency. Compare against a small authoritative distance calculation on representative edge cases, including the dateline when supported.

Compare alternatives

StageRoleCaution
Spatial indexReduce candidate setCell boundaries need neighbors
Exact distanceHonor radiusCoordinate system matters
RankingOrder useful resultsStable pagination policy
Source recordCurrent truthSearch may lag

A design-changing exercise

The nearest business lies across a cell edge. How do you avoid missing it?

Show answer and explanation

Answer: Query all cells intersecting the search region, then refine by exact distance. One containing-cell lookup is not a complete radius search.

Design workshop: exact radius and nearest-K are different queries

Core scope is nearby business search, category/hours filters, details and reviews. Personalized advertising is excluded. Assume p95 under 200 ms for a bounded radius, business updates searchable within one minute and current owner authorization for edits. Density determines candidate cost, so cap radius and page size explicitly.

Choose PostGIS geography with a spatial GiST index for the initial design rather than hand-building geohash traversal. Store a point using longitude/latitude in that order and meters for geography distance. Add business_categories(business_id,category_id), opening_intervals(business_id,time_zone,weekday,start_local,end_local) and exceptional_hours(date,intervals). A weekly local schedule must apply the business timezone and exceptions; a UTC-only daily interval mishandles clock changes.

sql
SELECT id, ST_Distance(position, :query_geography) AS meters
FROM businesses
WHERE status='active'
  AND ST_DWithin(position, :query_geography, :radius_meters)
ORDER BY meters, id
LIMIT :page_limit;

This radius query is exact under its chosen geometry, not a proof of arbitrary globally nearest results. If scaling to a cell projection, enumerate cells intersecting the search circle, collect candidates and filter exact distance. For nearest K, visit cells by a valid minimum-distance bound. Stop only after K eligible candidates exist and every unvisited cell's lower bound is farther than the current Kth result. A popularity-ranked query cannot use a distance-only stopping proof if distant candidates can win by popularity.

Cell candidates and exact circular filtering. A nearby business across a boundary must still be found.
Scroll to inspect the diagram, or open it at full size.
Nearest-2 expansion in a flat teaching coordinate system. First cell bound 0 m / 100 m and 900 m / Current second = 900; continue; Adjacent cell bound 10 m / 30 m and 200 m / Current nearest two = 30,100; Unvisited cells bound >= 150 m / No point can beat 100 m / Safe stop for pure nearest-distance ranking; Same geometry with popularity score / A farther point may score higher / Distance stop no longer proves top ranking
Scroll to inspect the diagram, or open it at full size.

Figure — Nearest-2 expansion in a flat teaching coordinate system.

For small distances a flat local projection can explain the example; production uses declared geodesic semantics, dateline handling and a tested library. A dense downtown cell may contain thousands of businesses: use adaptive precision or the indexed radius query and enforce bounded work. A signed query snapshot/cursor pins filters and ordering; current active status is rechecked before hydration.

Review edits update aggregates once. Reviewer to Review authority: Edit review r7 from 2 stars to 5 at expected version 3; Review authority to Outbox: Commit version 4 and event carrying old/new rating; Outbox to Rating projector: Project version-4 delta +3; count stays unchanged; Outbox to Rating projector: Repeated event version 4; Rating projector to Rating projector: Already applied; no second +3; Review authority to Reviewer: Conflicting edit gets 409 with current review version
Scroll to inspect the diagram, or open it at full size.

Figure — Review edits update aggregates once.

Each review has one owner and optionally unique(business,user) if the product permits one active review per user. Projection applies ordered review versions transactionally, or recomputes from current source on a version gap. New review increments sum and count; edit changes only sum; deletion subtracts prior rating and count. Stale events cannot undo a newer edit. Monitor boundary recall, candidates scanned, exact-filter rejection, opening-hour errors and aggregate reconciliation.

Exercise: Two reviews at 2 and 4 give average 3. The first becomes 5 and its event repeats. What is the result?

Show answer and explanation

Answer: Sum becomes 9, count remains 2, average is 4.5. Applying +3 twice would incorrectly produce 6. A per-review version/identity or recomputation is needed.

PostGIS ST_DWithin documents indexed distance filtering and geometry/geography units.

Technical references

PostgreSQL transaction isolation and concurrent updates.

11:00Self-guided practice timer
The timer resets when you leave this page. Save your design separately.
Your challenge

What evidence would show that the search index is causing poor nearby results?

Your design draft

Clarify assumptions, explain your approach, and test the difficult cases. Save your draft, then compare it with the study notes.

Read study notes

Self-review checklist

Self-guided practice. Automated AI feedback and code execution are not connected.