Learning pathsPricingA
SOLUTION REVIEW

Review: Yelp

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

Clarify this prompt before choosing components

Ask the highest-impact questions first, agree on priorities, and record the interviewer’s answers. If a detail is unspecified, state an assumption and explain which decision depends on it. The numbers in this worked lesson are exercise assumptions, not company facts.

Ask the interviewerWhy the answer changes the design
Nearby business search, reviews or reservations?Do not silently mix eventual search with transactional inventory.
Radius, ranking, geo accuracy and popular-city traffic?Spatial prefilter, exact distance and bounded ranking work are different stages.
Review edits/moderation and freshness?Versioned source records and index repair define what a user can see.

Use the Interview Playbook for the shared 45-minute sequence and fresher, intermediate, senior and staff evidence. Start with one complete operation. Extend the answer with the failure/recovery traces below, then defend a workload-specific alternative and a measurable rollout. Scope and evidence matter more than a large component list.

Yelp: Understand the building blocks

Choose a mechanism because it satisfies a requirement. These explanations describe the exercise design, not undisclosed implementation choices at the named company.

Yelp: Quick vocabulary

TermMeaning and role in this exercise
API: Application Programming InterfaceThe contract for requests, responses and errors between components. An API route does not itself enforce every business invariant.
PK: Primary KeyThe declared row identity in a database schema; it does not automatically enforce every cross-row business rule.

Yelp: Spatial index and exact distance filter

What it means: An index that groups positions so a nearby query examines a bounded candidate set instead of scanning every location.

Why this problem needs it: A radius query needs bounded candidate lookup followed by exact filtering.

How to use it: Search cells or bounding regions that intersect the requested radius, including boundaries, then compute exact distance and current eligibility for candidates.

Example in this design: At radius 2, distance 1.41 qualifies and 2.69 does not.

When it fits: Useful when frequent nearby queries make a full scan too expensive.

Alternative and limits: A small dataset may need only a scan. Geohashes, quadtrees and spatial database indexes have different update, precision and query costs. Proximity does not imply availability.

Mechanism reference

Yelp: Inverted index and BM25 relevance

What it means: An inverted index maps searchable terms to matching documents. BM25 is a relevance-scoring family using term/document statistics; it ranks candidates rather than deciding access.

Why this problem needs it: Text/category queries need a matching/relevance path beyond distance alone.

How to use it: Tokenize under a declared analyzer, maintain postings from versioned documents, retrieve candidates and enforce current visibility before disclosure.

Example in this design: Find eligible “coffee” candidates, then apply requested geography and ranking.

When it fits: Useful when text queries should avoid scanning every post or document.

Alternative and limits: Database text search can fit a smaller baseline. An external search index adds lag, repair and operations; high score does not imply current authorization.

Yelp: Projection and materialized view

What it means: A projection is a derived read model built from authoritative facts; it improves a particular read path and can be rebuilt.

Why this problem needs it: Rating summaries avoid rescanning all reviews per listing read.

How to use it: Consume versioned facts with replay-safe updates, expose a watermark/revision, and compare or rebuild from the authoritative history.

Example in this design: Ratings 2 and 4 sum to 6; editing 2 to 5 yields sum 9 and count 2, not count 3.

When it fits: Useful when read shapes or volume justify duplicating computation/state.

Alternative and limits: Read authoritative rows directly for a simpler strongly current baseline. A stale projection must not grant revoked access or decide a strict inventory transition.

Yelp: Cache-aside, Redis and time to live (TTL)

What it means: A cache keeps reusable copies for faster reads. Cache-aside checks the cache, loads an authoritative source on a miss, then fills it. TTL is the declared entry lifetime.

Why this problem needs it: Popular listing summaries may be reused with visible freshness.

How to use it: Key by the correct tenant/object/version, retain an absolute freshness deadline, bound entry size, and apply the stated invalidation or version-fence policy. Redis is one possible in-memory implementation.

Example in this design: A delayed summary revision cannot overwrite a newer accepted rating view.

When it fits: Useful when repeated eligible reads justify memory and the tolerated staleness is explicit.

Alternative and limits: Direct indexed database reads may suffice. A cache is not automatically durable authority; shorter TTL does not prove immediate revocation.

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.
Three architecture decisions for Yelp, including the pressure each introduces.
Read the diagram

Filter nearby records / Store businesses and query a coarse spatial region. / A rectangular or cell candidate region includes false positives.; 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.; Scale the search projection / Use an indexed read model and caches with an explicit freshness policy. / Ranking caches can preserve closed or removed businesses.

Open original
Yelp · architecture decisions
Three architecture decisions for Yelp, including the pressure each introduces.

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.
Connected responsibilities for Yelp. Trace the authoritative and derived paths separately.
Read the diagram

Searcher to Discovery API: radius and filters; Discovery API to Business DB: business details; Owner to Business DB: update business hours; Business DB to Projection worker: business version; Projection worker to Spatial index: update spatial projection; Discovery API to Spatial index: intersecting cells

Open original
Yelp · connected architecture
Connected responsibilities for Yelp. Trace the authoritative and derived paths separately.

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.
Yelp · working baseline
Read the diagram

Search → intersecting cells → candidate businesses; Exact distance and filters → ranking → page; Review write → durable record → rating projection

Open original
Yelp · working baseline
Yelp: baseline request paths.

Yelp · working baseline

  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.
Yelp · scale and recovery paths
Read the diagram

Dense cells → finer resolution or spatial tree; Hot-area candidate cache → current status checks; Search replicas → bounded result candidates

Open original
Yelp · scale and recovery paths
Yelp: additional scaling and recovery paths.

Yelp · scale and recovery paths

  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.

Radius and named-region search use different final geometry checks after cell candidate retrieval.
Radius search and named-region search use different geometry
Read the diagram

A radius uses exact distance; a named region uses point-in-polygon containment.

Open original
Radius search and named-region search use different geometry
Radius and named-region search use different final geometry checks after cell candidate retrieval.

Radius search and named-region search use different geometry

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.
Proximity search · cells are only candidates
Read the diagram

A search circle crosses several grid cells. One valid nearby point is in the neighboring cell, and a candidate in an intersecting cell lies outside the circle.

Open original
Proximity search · cells are only candidates
Cell candidates and exact circular filtering. A nearby business across a boundary must still be found.

Proximity search · cells are only candidates

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
Nearest-2 expansion in a flat teaching coordinate system.
Read the diagram

Cell bound / Eligible exact distances / Decision; 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

Open original
Nearest-2 expansion in a flat teaching coordinate system
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

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
Review edits update aggregates once.
Read the diagram

Edit review r7 from 2 stars to 5 at expected version 3; Commit version 4 and event carrying old/new rating; Project version-4 delta +3; count stays unchanged; Repeated event version 4; Already applied; no second +3; Conflicting edit gets 409 with current review version

Open original
Review edits update aggregates once
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

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.

Requirement trace and verification

RequirementImplementing design blockVerification link
R1 — Complete the primary user journey within the stated scope.P01–P04; P09–P10.V1 — Exercise the successful journey and the excluded/boundary case stated in the scope.
R2 — Preserve the problem's authoritative data invariant under concurrency.P05–P06; P11–P12; DD1.V2 — Run the race/replay case below and assert the invariant at the durable authority.
R3 — Meet the declared scale and API behavior without unbounded work.P05–P08; P13–P14; relevant overload deep dives.V3 — Exercise the API errors/retry identity and recompute the workload assumption that drives partition or capacity.
R4 — Recover from the named failure without losing or duplicating the user-visible outcome.P15–P16; deep dives; Operations contract.V4 — Edit and delete a review, replay its events, and delay indexing; rating aggregates eventually reconcile without duplicate reviews.

Operational contract

AreaDecision and signals
SLIsSearch p99; candidate count; exact-distance work; index lag; stale-business filtering.
Overload limitsCap cells expanded, candidate businesses, review fanout, and per-query sort/rank budget.
RecoveryRebuild spatial projection from business records; version updates to prevent stale location or hours from overwriting newer state.
Access controlsRestrict owner mutations and protect user coordinates/review abuse controls.
Dominant costSpatial index memory, location updates, and review/search traffic.

Senior-level interviewer follow-ups

Question: A nearest-K search stops after one geospatial cell. How do you know no unsearched cell has a closer result?

Show answer and explanation

Answer: Maintain a lower bound on distance to every unsearched cell and stop only when that bound exceeds the current Kth exact distance. Otherwise expand the search.

Question: How should 'open now' behave across daylight-saving changes?

Show answer and explanation

Answer: Store a venue timezone and local weekly intervals plus dated exceptions. Evaluate current local time using that zone; UTC offsets alone do not encode future daylight-saving transitions.

A 60-second design answer

I would use text/category and spatial indexes to retrieve a bounded candidate set, then apply exact distance and current filters. For nearest-K, expand cells until the lower bound to unsearched cells exceeds the current Kth distance. Hours use venue-local time and dated exceptions. I would monitor candidate amplification, geo-cell skew, stale business data, and query latency.

Proximity Search Elasticsearch

Technical references

PostgreSQL transaction isolation and concurrent updates.

Update rating sums without changing review ownership

Two reviews have stars 2 and 4: sum=6,count=2,mean=3. The first author edits 2 to 5. In the versioned transaction, change sum by +3 and keep count=2; new mean=4.5. A replay of the same edit version contributes nothing further. A unique user/business review key prevents duplicate ownership when the product allows one review per pair.

Contract / pseudocode
before: [2,4]; sum 6; count 2
edit review r1 v2: 2 -> 5
after: [5,4]; sum 9; count 2; average 4.5
before: [2,4]; sum 6; count 2; edit review r1 v2: 2 -> 5; after: [5,4]; sum 9; count 2; average 4.5
Update rating sums without changing review ownership
Read the diagram

before: [2,4]; sum 6; count 2; edit review r1 v2: 2 -> 5; after: [5,4]; sum 9; count 2; average 4.5

Open original
Update rating sums without changing review ownership
before: [2,4]; sum 6; count 2; edit review r1 v2: 2 -> 5; after: [5,4]; sum 9; count 2; average 4.5

Update rating sums without changing review ownership

Search combines spatial candidates, exact distance, text/category and visibility filters. A nearby business across a cell boundary must remain discoverable. Name-based neighborhoods require a defined geometry/lookup, not simply treating a name as coordinates. Derived search ratings need revision/rebuild and eventual freshness, while authoritative review edits remain correct.

Show answer and explanation

Answer: Averaging regional/shard averages without their review counts can give a wrong global rating. Keep sums and counts or another mathematically valid merge representation.

Decision review: Yelp

Yelp: What it is

A nearby-business search combines spatial/text candidates, exact filters, ranking and authorized review/rating updates.

Yelp: Why it is needed

A coarse cell can include out-of-radius results or omit neighbors; aggregate ratings can be corrupted by replayed edits.

Yelp: When to use it

Choose radius search or nearest-K explicitly, because they have different candidate and stopping conditions.

Yelp: How to use it

Use an appropriate spatial access path, exact distance and eligibility checks. Keep canonical review ownership and version-aware sum/count changes separate from the search projection.

Yelp: Compare an alternative

A fixed small cell set may bound work but cannot promise global nearest-K without a completeness argument. A larger candidate search trades work for coverage under the declared contract.

Yelp: Worked decision exercise

The following inputs and policies are original exercise assumptions; they are not measurements or undisclosed company behavior.

For a flat-plane radius 2, A=(1,1) is about 1.41 away and B=(1.9,1.9) about 2.69. Ratings 2 and 4 sum to 6; editing 2 to 5 increases the sum to 9 with count still 2, and replay must not add three again.

Yelp: Radius 2: A at distance 1.41 qualifies; B at 2.69 does not; Ratings 2,4: sum 6 and count 2; Edit 2 to 5: sum 9 and count 2; Duplicate edit must not increase sum again
Yelp: a concrete state and recovery trace under the exercise assumptions.
Read the diagram

Radius 2: A at distance 1.41 qualifies; B at 2.69 does not; Ratings 2,4: sum 6 and count 2; Edit 2 to 5: sum 9 and count 2; Duplicate edit must not increase sum again

Open original
Yelp: worked example
Yelp: Radius 2: A at distance 1.41 qualifies; B at 2.69 does not; Ratings 2,4: sum 6 and count 2; Edit 2 to 5: sum 9 and count 2; Duplicate edit must not increase sum again

Yelp: a concrete state and recovery trace under the exercise assumptions.

Can a stale search document determine whether a closed or hidden business is currently eligible?

Show answer and explanation

Answer: Only within the declared freshness policy. A strict suppression rule needs a current serving check at an authority that can enforce it. Keep distance, ranking and eligibility separate, then repair the index using revisions and deletion markers.

Yelp: Check the design

Test cell boundaries, exact radius, tie-breaking rank and replayed review corrections. Monitor candidate rejection and projection lag instead of assuming a fast index is correct.

Your study notes