题目重点:DoorDash VO 系统设计题详解:食物平均分、评论、用户投票、奖励资格,重点是 Schema 唯一约束、幂等发奖和聚合一致性。
题意与假设
这道练习题保留了面经中值得训练的核心约束,并将需要澄清的条件单独列出。现场拿到变体时,先和面试官确认这些条件。
- Top reviewer并发奖的变体未给排名指标/周期/资格。练习可以按有效评论净赞数在一个周期内聚合author得分,规则和周期须显式版本化,不以评论达到阈值奖励代替作者TopK奖励。
- 可见题目未明确出打赏阈值、金额或资格时间窗。训练契约假设只有已完成订单的购买者能写一条对应 food 的 review;投票者不能投自己的 review,单用户对同一 review 当前最多一票。
- 评论评分取 1–5 星;平均分只统计可见且有效的评论。打赏定义为某一规则版本下评论首次达到净赞数阈值时发一次,具体阈值和金额由产品配置。
- 删评、改评和撤销投票的历史资格要产品决定。示例选择奖励一旦依法发出不自动追回,并把事后撤销交给人工风控流程。
解题路线
- 作者排行把已验证review投票差量累积到(authorId,period,ruleVersion)。维护可重算事件与作者score,读TopK以(score降序,authorId)稳定tie分页;反作弊过滤无效票时也需扣回差量。热榜异步更新,周期关账时以权威事件截止位点重算再发奖。
- 周期获奖以(period,ruleVersion,authorId)唯一,reward ledger/outbox事务写入;重放或重复榜单生成不重复支付。奖项阈值跨越的评论奖励和周期作者排名奖励是两个独立资格键,不能共享一个reviewId唯一约束。
- 把 review 与 vote 分成两张表:review 主键 review_id,包含 author_id、food_id、order_item_id、rating、状态、版本;vote 以 (review_id,voter_id) 唯一,value 为 +1 或 -1。创建评论另给 (order_item_id,author_id) 唯一约束,防重试重复发评。
- 写评论、改评分、删评论以事务更新源表并写 outbox 事件;异步维护 food_rating_stats(count,sum)、review_vote_stats(up,down)。读页面时显示聚合版本/更新时间,必要时回源修正;不能让缓存里的旧聚合覆盖新版本。
- 投票接口是对目标状态的 PUT,而非每点一次就加一。事务中 upsert 唯一行、计算旧票到新票的差量并写 outbox;重复请求相同状态无差量。资格服务消费计数变化,用 (review_id,rule_version) 唯一奖励记录原子抢占,账务 ledger 以同一键幂等入账。
手动走一遍
食物 F 有两个有效评分 4、5,stats(count=2,sum=9),页面平均分 4.5。评论 R 先获 A、B 两个赞,A 再次提交 upvote 是零增量;B 改为 downvote 时净赞从 2 变为 0。若某规则的阈值是净赞 2,第一次达到时 reward 表插入 (R,version),后续重试或重新达标均不会重复发奖。阈值 2 仅用于演示,不是题目披露值。
规模与取舍
单次评论/投票写入在适当主键与唯一索引下约 O(log N) 存储操作;更新聚合是 O(1) 差量。页面按 food_id 分页检索评论约 O(log N+K),K 为返回条数;跨大规模热 food 的计数可分片汇总,但会增加读取与奖励判定延迟。
易错点与追问
容易失分的边界
- 不能把用户写 review 和用户投票混成同一条关系;两者权限、唯一键、可修改动作完全不同。
- 仅靠应用层先查是否投过票会在并发下重复计数,必须在数据库唯一约束和事务差量上兜底。
- 异步聚合可能重复、乱序或延迟;发奖不能只看客户端展示的缓存计数,须有可重放事件、单调版本与最终一致性修正。
- 奖励涉及资金或积分,应在权威 ledger 记录,不以通知是否成功判断是否已经发放。
继续深挖
- 如果关账后判定刷票,是追回、冻结还是下一期抵扣?规则版本和申诉状态如何跟ledger关联?
- 若评论一秒收到大量票,review_vote_stats 成为热行,可先分片计数,再在达到阈值附近触发权威重算与唯一奖励插入。
- 若用户删除订单或 food 下架,需定义评论可见性、历史评分是否回滚、奖励是否撤销,以及审核/反作弊链路。
- 若产品要求实时准确平均分,可以在事务内同步更新 count/sum;但跨热 food 写入争用更高,应按规模和延迟目标取舍。
