Functional Specifications (In-Scope)
- Rating Submissions: Processes 1-5 star ratings paired with descriptive comments.
- Verified Purchase Badges: Interfaces with delivery registries to lock a green verified stamp on valid reviews.
- Abusive Spam Blockades: Evaluates velocity checks and text similarities to suppress duplicate reviewer patterns.
- Calculated Weighted Star Ratings: Weights verified customer ratings at 1.5x relative to unverified users.
Out-of-Scope Boundaries
- Full-Text Semantic Translation: Multi-lingual translator pipelines are decoupled.
- Direct User Social Follows: Does not record social graphs between different reviewers.
Production reference implementations demonstrating duplicate checkers, verified tags, and aggregate calculations:
// ─── JAVA BLUEPRINT ──────────────────────────────────────────────────────────
import java.util.*;
import java.util.concurrent.*;
import java.util.concurrent.atomic.AtomicInteger;
enum ReviewStatus {
ACTIVE,
FLAGGED_SPAM,
UNDER_REVIEW
}
class Review {
private final String reviewId;
private final String userId;
private final String productId;
private final int rating;
private final String reviewText;
private final boolean isVerified;
private ReviewStatus status;
private final long createdAt;
private final AtomicInteger upvotes = new AtomicInteger(0);
private final AtomicInteger downvotes = new AtomicInteger(0);
public Review(String userId, String productId, int rating, String reviewText, boolean isVerified) {
this.reviewId = UUID.randomUUID().toString();
this.userId = userId;
this.productId = productId;
this.rating = rating;
this.reviewText = reviewText;
this.isVerified = isVerified;
this.status = ReviewStatus.ACTIVE;
this.createdAt = System.currentTimeMillis();
}
public String getReviewId() { return reviewId; }
public String getUserId() { return userId; }
public String getProductId() { return productId; }
public int getRating() { return rating; }
public String getReviewText() { return reviewText; }
public boolean isVerified() { return isVerified; }
public ReviewStatus getStatus() { return status; }
public void setStatus(ReviewStatus status) { this.status = status; }
public long getCreatedAt() { return createdAt; }
public int getUpvotes() { return upvotes.get(); }
public int getDownvotes() { return downvotes.get(); }
public void upvote() { upvotes.incrementAndGet(); }
public void downvote() { downvotes.incrementAndGet(); }
public double getHelpfulScore() {
int up = upvotes.get();
int down = downvotes.get();
if (up + down == 0) return 0.0;
return (double) up / (up + down);
}
}
interface SpamFilter {
boolean isSpam(Review review);
}
class ContentDuplicationFilter implements SpamFilter {
private final Map<String, List<String>> userReviewTexts = new ConcurrentHashMap<>();
@Override
public boolean isSpam(Review review) {
List<String> existing = userReviewTexts.computeIfAbsent(review.getUserId(), u -> new CopyOnWriteArrayList<>());
for (String text : existing) {
if (calculateSimilarity(text, review.getReviewText()) > 0.8) {
return true;
}
}
existing.add(review.getReviewText());
return false;
}
private double calculateSimilarity(String s1, String s2) {
if (s1 == null || s2 == null) return 0.0;
Set<String> words1 = new HashSet<>(Arrays.asList(s1.toLowerCase().split("\\s+")));
Set<String> words2 = new HashSet<>(Arrays.asList(s2.toLowerCase().split("\\s+")));
Set<String> intersection = new HashSet<>(words1);
intersection.retainAll(words2);
Set<String> union = new HashSet<>(words1);
union.addAll(words2);
if (union.isEmpty()) return 0.0;
return (double) intersection.size() / union.size();
}
}
class VelocityAbuseFilter implements SpamFilter {
private final Map<String, Long> userLastSubmitTime = new ConcurrentHashMap<>();
private static final long COOLDOWN_MS = 5000;
@Override
public boolean isSpam(Review review) {
long now = System.currentTimeMillis();
Long lastSubmit = userLastSubmitTime.get(review.getUserId());
if (lastSubmit != null && (now - lastSubmit) < COOLDOWN_MS) {
return true;
}
userLastSubmitTime.put(review.getUserId(), now);
return false;
}
}
class RatingAggregation {
private final double weightedAverage;
private final double simpleAverage;
private final int totalCount;
public RatingAggregation(double weightedAverage, double simpleAverage, int totalCount) {
this.weightedAverage = weightedAverage;
this.simpleAverage = simpleAverage;
this.totalCount = totalCount;
}
public double getWeightedAverage() { return weightedAverage; }
public double getSimpleAverage() { return simpleAverage; }
public int getTotalCount() { return totalCount; }
}
class RatingAggregator {
public RatingAggregation aggregate(Collection<Review> reviews) {
double sumVerified = 0;
int countVerified = 0;
double sumUnverified = 0;
int countUnverified = 0;
for (Review r : reviews) {
if (r.getStatus() != ReviewStatus.ACTIVE) {
continue;
}
if (r.isVerified()) {
sumVerified += r.getRating();
countVerified++;
} else {
sumUnverified += r.getRating();
countUnverified++;
}
}
int totalCount = countVerified + countUnverified;
if (totalCount == 0) {
return new RatingAggregation(0.0, 0.0, 0);
}
double weightedNum = (1.5 * sumVerified) + sumUnverified;
double weightedDen = (1.5 * countVerified) + countUnverified;
double weightedAverage = weightedNum / weightedDen;
double simpleAverage = (sumVerified + sumUnverified) / totalCount;
return new RatingAggregation(weightedAverage, simpleAverage, totalCount);
}
}
class ReviewRanker {
public List<Review> sort(List<Review> reviews) {
List<Review> sorted = new ArrayList<>(reviews);
sorted.sort((r1, r2) -> {
if (r1.getStatus() != r2.getStatus()) {
return r1.getStatus() == ReviewStatus.ACTIVE ? -1 : 1;
}
int compareVotes = Double.compare(r2.getHelpfulScore(), r1.getHelpfulScore());
if (compareVotes != 0) {
return compareVotes;
}
return Long.compare(r2.getCreatedAt(), r1.getCreatedAt());
});
return sorted;
}
}
class ReviewManager {
private final Map<String, List<Review>> productReviews = new ConcurrentHashMap<>();
private final List<SpamFilter> spamFilters = new CopyOnWriteArrayList<>();
private final RatingAggregator aggregator = new RatingAggregator();
private final ReviewRanker ranker = new ReviewRanker();
public void addSpamFilter(SpamFilter filter) {
spamFilters.add(filter);
}
public boolean submitReview(Review review) {
for (SpamFilter filter : spamFilters) {
if (filter.isSpam(review)) {
review.setStatus(ReviewStatus.FLAGGED_SPAM);
System.out.println("🚨 SPAM ALERT: Review by " + review.getUserId() + " flagged as spam.");
productReviews.computeIfAbsent(review.getProductId(), p -> new CopyOnWriteArrayList<>()).add(review);
return false;
}
}
productReviews.computeIfAbsent(review.getProductId(), p -> new CopyOnWriteArrayList<>()).add(review);
System.out.println("✅ REVIEW ACCEPTED: Review by " + review.getUserId() + " successfully submitted.");
return true;
}
public RatingAggregation getProductRating(String productId) {
List<Review> reviews = productReviews.getOrDefault(productId, Collections.emptyList());
return aggregator.aggregate(reviews);
}
public List<Review> getSortedReviews(String productId) {
List<Review> reviews = productReviews.getOrDefault(productId, Collections.emptyList());
return ranker.sort(reviews);
}
}
public class Main {
public static void main(String[] args) {
System.out.println("=== JAVA REVIEW & RATING SYSTEM SIMULATION ===");
ReviewManager manager = new ReviewManager();
manager.addSpamFilter(new ContentDuplicationFilter());
manager.addSpamFilter(new VelocityAbuseFilter());
String productId = "PROD-100";
Review r1 = new Review("alice_dev", productId, 5, "Absolutely outstanding quality. Easily worth the price.", true);
Review r2 = new Review("dan_commerce", productId, 4, "Very solid construction. A bit tight on the ears but overall great aviators.", true);
Review r3 = new Review("unverified_guy", productId, 2, "Decent glasses but delivery took too long.", false);
manager.submitReview(r1);
manager.submitReview(r2);
manager.submitReview(r3);
r1.upvote(); r1.upvote(); r1.upvote(); r1.downvote();
r2.upvote(); r2.upvote();
RatingAggregation aggBefore = manager.getProductRating(productId);
System.out.println("\nInitial Aggregated Rating:");
System.out.println(" - Total Active Reviews: " + aggBefore.getTotalCount());
System.out.printf(" - Simple Average Rating: %.2f\n", aggBefore.getSimpleAverage());
System.out.printf(" - Weighted Average Rating: %.2f (Verified purchases given 1.5x weight)\n", aggBefore.getWeightedAverage());
System.out.println("\nSubmitting spam review with same content from same user...");
Review rSpamDupe = new Review("alice_dev", productId, 5, "Absolutely outstanding quality. Easily worth the price.", true);
manager.submitReview(rSpamDupe);
System.out.println("\nSubmitting rapid consecutive reviews (velocity check)...");
Review rVelocity1 = new Review("fast_typer", productId, 5, "Great product!", false);
Review rVelocity2 = new Review("fast_typer", productId, 5, "Loved the packaging too!", false);
manager.submitReview(rVelocity1);
manager.submitReview(rVelocity2);
System.out.println("\nSorted Active Reviews by Helpfulness & Date:");
List<Review> sorted = manager.getSortedReviews(productId);
for (Review r : sorted) {
if (r.getStatus() == ReviewStatus.ACTIVE) {
System.out.printf(" - User: %s | Rating: %d | Helpful Ratio: %.2f | Verified: %s | Text: \"%s\"\n",
r.getUserId(), r.getRating(), r.getHelpfulScore(), r.isVerified(), r.getReviewText());
}
}
System.out.println("=== END OF JAVA SIMULATION ===");
}
}