How to Design a Review and Rating System
Learn how to design a review and rating system with incremental aggregates, verified purchases, and async spam moderation.
Expected Interview Answer
A review and rating system stores individual reviews as immutable, append-mostly records tied to a verified purchase or interaction, maintains a precomputed aggregate rating updated incrementally rather than recalculated from all reviews on every read, and runs abuse/spam detection asynchronously so posting stays fast.
Each review (rating, text, author, target item, timestamp) is written once and rarely mutated in place — edits create a new version or a moderation flag rather than silently overwriting history — and is linked to proof of a genuine interaction (a verified purchase or completed booking) to reduce fake reviews. Because average rating and count are read far more often than individual reviews are written, the aggregate (sum, count, and derived average, sometimes a distribution histogram) is maintained incrementally with each new review — updating a running sum and count — rather than recomputed by scanning every review on each page load, which would not scale for popular items. Spam and abuse detection (bot patterns, review bombing, profanity) runs asynchronously after the review is accepted so the user-facing write path stays fast, with a queue feeding a moderation pipeline that can retroactively hide or flag content. Read paths are heavily cached since review pages are read far more than written, and pagination/sorting (most helpful, most recent, highest/lowest rating) is served from a denormalized read model rather than joining across raw review tables on every request.
- Verified-purchase linkage reduces fake or incentivized reviews
- Incremental aggregate updates keep rating lookups fast regardless of review volume
- Asynchronous moderation keeps the review submission path fast for users
- Denormalized, cached read models make sorting and browsing reviews scale well
AI Mentor Explanation
A review and rating system is like a stadium’s post-match fan feedback wall, where each comment is pinned once and rarely erased, only ever flagged or removed by staff if it breaks the rules. The scoreboard showing overall fan satisfaction updates incrementally as each new comment comes in, rather than staff re-reading every comment on the wall each time someone asks for the average, mirroring an incrementally maintained aggregate rating. Only fans who actually held a ticket for that match can post feedback, similar to linking reviews to verified purchases. Suspicious spam comments get flagged by staff after the fact rather than blocking the wall from accepting new comments while they are reviewed, mirroring asynchronous moderation.
Step-by-Step Explanation
Step 1
Store reviews as near-immutable records
Each review is written once, linked to a verified purchase/interaction, and edits are tracked rather than silently overwritten.
Step 2
Maintain aggregates incrementally
Update a running sum, count, and derived average (and histogram) with each new review instead of recomputing from all reviews on read.
Step 3
Moderate asynchronously
Accept the review immediately for a fast write path, then run spam/abuse/bot detection in a background queue that can retroactively hide content.
Step 4
Serve reads from a cached, denormalized model
Sorting (most helpful, most recent) and pagination are served from a cached read model, not raw joins on every request.
What Interviewer Expects
- Proposes incremental aggregate maintenance instead of recomputing ratings on every read
- Links reviews to verified purchases/interactions to reduce fake reviews
- Runs spam/abuse moderation asynchronously to keep the write path fast
- Recognizes reviews are read far more than written, motivating heavy caching
Common Mistakes
- Recomputing the average rating from all reviews on every page load, which does not scale
- Allowing reviews with no link to a verified purchase, enabling easy fake reviews
- Running synchronous moderation on the write path, slowing down review submission
- Silently overwriting edited reviews with no audit trail
Best Answer (HR Friendly)
“A review and rating system needs to keep every review as a lasting record while making sure the overall star rating stays fast to look up even with millions of reviews, which it does by updating the average incrementally instead of recalculating it from scratch every time. It also checks that reviews come from real customers and screens for spam or fake reviews in the background so posting a review still feels instant.”
Code Example
def submit_review(product_id, user_id, rating, text):
if not purchase_repo.has_verified_purchase(user_id, product_id):
raise NotEligibleError("review requires a verified purchase")
review = review_repo.insert(
product_id=product_id,
user_id=user_id,
rating=rating,
text=text,
status="published",
)
# Incrementally update the aggregate instead of scanning all reviews
db.execute(
"""
UPDATE product_rating_aggregates
SET rating_sum = rating_sum + %s,
rating_count = rating_count + 1
WHERE product_id = %s
""",
[rating, product_id],
)
# Fire-and-forget: async moderation does not block the response
moderation_queue.enqueue("scan_review", review_id=review.id)
return review
def get_aggregate_rating(product_id):
row = db.query_one(
"SELECT rating_sum, rating_count FROM product_rating_aggregates WHERE product_id = %s",
[product_id],
)
if not row or row.rating_count == 0:
return {"average": None, "count": 0}
return {"average": row.rating_sum / row.rating_count, "count": row.rating_count}Follow-up Questions
- How would you handle a review being retroactively removed by moderation after the aggregate already counted it?
- How would you detect coordinated review bombing versus genuine negative sentiment?
- How would you support sorting reviews by “most helpful” at scale?
- How would you shard review storage for an item with millions of reviews?
MCQ Practice
1. Why maintain the average rating incrementally instead of recomputing it from all reviews on each read?
Ratings are read far more often than reviews are written, so incrementally updating a running sum/count avoids expensive full scans on every read.
2. Why link reviews to a verified purchase or completed interaction?
Requiring proof of a genuine purchase or interaction is a strong signal against fake or paid-for reviews.
3. Why should spam/abuse detection run asynchronously after a review is submitted?
Running moderation checks in a background queue avoids delaying the user-facing write, while still allowing retroactive flagging or removal.
Flash Cards
Why maintain rating aggregates incrementally? — Recomputing from all reviews on every read does not scale; an incremental sum/count does.
Why require a verified purchase for reviews? — It substantially reduces fake or incentivized reviews.
Why run moderation asynchronously? — To keep the review write path fast while still catching spam/abuse in the background.
Why cache the read path heavily? — Review pages are read far more often than reviews are written.