Design Yelp
Variants:
High-Level Design
Yelp System Design Requirements
Functional Requirements
Business Search
Users should be able to search for businesses by keyword, location, and category.
Reviews and Ratings
Users should be able to read reviews and ratings for businesses, and submit their own reviews and ratings.
Business Listings
The system should display detailed information about businesses, including address, photos, and user reviews.
Non-Functional Requirements
High Availability
The platform must be highly available to users for searching and to businesses for managing their listings.
Low Latency Search
Search results must be returned quickly (e.g., under 200ms) to provide a good user experience.
Data Consistency
While some eventual consistency is acceptable (e.g., for new reviews appearing in search), the average rating for a business should be updated in near real-time after a new review is submitted.
CAP Theorem Trade-offs
Trade-off Explanation:
Yelp leans towards Consistency and Availability. While search results can be eventually consistent, it's important for review and rating data to be as up-to-date as possible. The system must remain available for users to search and read reviews.
Scale Estimates
API Design
Search for businesses by term, location, and category.
Request Body
{ "term": "string", "location": "string", "category": "string" }
Response Body
[{ "business_id": "string", "name": "string", "rating": 4.5, "review_count": 123 }]
Get detailed information for a specific business.
Response Body
{ "business_id": "string", "name": "string", "address": "string", "reviews": [...] }
Submit a review for a business.
Request Body
{ "user_id": "string", "business_id": "string", "rating": 5, "text": "string" }
Response Body
{ "review_id": "string", "status": "success" }
Database Schema
Our database needs to store information about businesses, user reviews, and potentially location data. A relational database like PostgreSQL could work, but a NoSQL database like DynamoDB might be better for handling the scale of user-generated content. The diagram shows a primary database and a separate Elasticsearch index for searching.
Business
Reviews
Locations
Business and Review Services
The core logic of our application is split between two main microservices, as shown in the architecture diagram. This separation of concerns allows for independent development, scaling, and deployment.
Business Service: This service is the definitive source of truth for all business-related information. Its responsibilities include:
- CRUD Operations: Handling the creation, reading, updating, and deletion of business profiles.
- Data Ownership: It owns the
Business
table in our primary database. Any other service that needs business information must query this service's API. - Data Enrichment: It could be responsible for background jobs that enrich business data, such as fetching photos from an external API or standardizing addresses.
Review Service: This service manages all aspects of user reviews and ratings.
- Review Submission: It exposes an endpoint for users to submit new reviews, which includes a star rating and text content.
- Rating Aggregation: A critical function of this service is to update the overall rating of a business whenever a new review is submitted. As the diagram indicates, this is a synchronous operation. When a review is saved to the
Reviews
table, the Review Service immediately recalculates theavg_rating
and increments thenum_ratings
in theBusiness
table for the corresponding business. This ensures that the rating displayed to users is always strongly consistent. - Trade-offs: While synchronous updates provide immediate consistency, they can introduce latency to the review submission process and create a tight coupling between the Review and Business services. An alternative approach would be to use a message queue. The Review Service would publish a "review_added" event, and a separate worker process would consume this event to update the business rating asynchronously. This would improve the responsiveness of the review submission endpoint at the cost of a slight delay (eventual consistency) in the rating update.
Search and Geospatial Indexing
A powerful and flexible search experience is at the heart of Yelp. Users expect to find businesses by name, category, location, and keywords within reviews. A standard relational database query would be far too slow and inflexible for this. We need a dedicated search index. Here are two potential solutions for this problem.
Elasticsearch (Recommended)
Elasticsearch is a distributed search and analytics engine built on top of Apache Lucene. It is the ideal solution for Yelp's needs because it natively supports all the required query types in a single, scalable system.
- Full-Text Search: It uses an inverted index to provide fast, relevance-ranked results for keyword searches across business names, descriptions, and user reviews.
- Geospatial Queries: It has robust support for
geo_point
andgeo_shape
data types, allowing for efficient queries like "find all cafes within a 1-mile radius" or "find all parks in this neighborhood." - Faceted Search & Aggregations: Elasticsearch makes it easy to implement the filters (category, price, rating) that are crucial to the Yelp experience. It can quickly aggregate data to show, for example, the count of businesses in each category that match a search query.
- Integration: As shown in the diagram, we can keep Elasticsearch synchronized with our primary database using a Change Data Capture (CDC) pipeline. Tools like Debezium can monitor our database's transaction log and stream any changes to a Kafka topic, which then feeds into Elasticsearch. This keeps our search index up-to-date without burdening our application services.
Geohashing + Custom Index
If we wanted to build a more custom solution without relying on a comprehensive search engine like Elasticsearch, we could combine multiple technologies.
- Geospatial Search: We could use the Geohashing technique, as discussed in the Uber system design. Each business's location would be converted into a geohash string, and we would store this in our database (e.g., DynamoDB or PostgreSQL). To find nearby businesses, we would query for all businesses whose geohash shares a common prefix with the user's location's geohash.
- Text Search: For full-text search on reviews and business names, we would need a separate index. We could use a simpler text search library or a managed service, but we would be responsible for building and maintaining the index ourselves.
- Complexity: While this approach is feasible, it forces us to manage and scale two separate indexing systems (one for geo, one for text). The complexity of combining results from these different systems makes Elasticsearch a much more practical and powerful choice for a feature-rich application like Yelp.
Complete Design
Putting it all together, the Yelp system relies on a service-oriented architecture. The client interacts with an API Gateway, which routes requests to the appropriate microservice (Business or Review). The services interact with a primary database for transactional data. For the complex search requirements, data is replicated to an Elasticsearch cluster via a Change Data Capture pipeline, allowing for fast and flexible searching without impacting the performance of the primary database.