SWE · VO System Design

Uber VO 司机评论排行榜:去重评分、时间窗与公平排序

题目只给基于 reviews 的司机 leaderboard;以明确训练假设设计评论事实表、撤销/修改、窗口聚合、榜单索引、防刷与小样本可信度。

题目重点:题目只给基于 reviews 的司机 leaderboard;以明确训练假设设计评论事实表、撤销/修改、窗口聚合、榜单索引、防刷与小样本可信度。

题意与假设

这道练习题保留了面经中值得训练的核心约束,并将需要澄清的条件单独列出。现场拿到变体时,先和面试官确认这些条件。

  • 训练场景:乘客行程结束后可对一位司机给 1–5 分及可选文字,按城市展示近 30 天的 Top 司机;只统计已完成且通过风控的行程,每 trip 只保留一条有效评论版本。
  • 榜单先用平均分排序,至少 20 条有效评论才入榜;同分按评论数再按 driverId 稳定打破。门槛和窗口只是为了说明小样本处理,不是题目给的规则。
  • 示例规模为每天 100 万条新评论、每秒 1 万次榜单查询的容量讨论,需以实际业务流量重估;评论文本审核与用户隐私应有独立政策。

解题路线

  1. 事实表存 reviewId、tripId、driverId、riderId、rating、eventTime、version、status;数据库对 tripId 的有效评论设置唯一约束。评分提交校验行程参与身份和完成状态,重试用 reviewId/attemptKey 幂等,修改/撤销产生版本化事件而非静默覆盖旧事实。
  2. 聚合器按 driverId×城市×时间桶维护有效评论 sum/count,修改旧评分时做负向修正再加新值;迟到/申诉翻转 status 时回填原发生窗口。可从事实表定期重建并对账,防事件重复或漏投递把榜单带偏。
  3. 固定 30 天榜单把桶到期和新评论增量地更新每司机分子/分母,再更新有序索引;按城市分区,查询 Top K 从索引读取并附 asOf。若任意历史时间窗也要求精确 Top,单一 30 天索引不够,应读时间桶或原事件并接受更高延迟。
  4. 排名政策需和产品风险一起确定:少量五星司机不能天然压过稳定高分司机,可用最低样本数、贝叶斯平滑或置信下界;这些会改变榜单定义,须与面试官确认而非偷换‘平均分’。异常评论、刷单关联、申诉和人工复核应能解释某司机名次变化。
  5. 地区流量和评价分布不同,跨城比较可能不公平;明确 leaderboard 是城市内、时段内还是全站,监控榜单更新延迟、被过滤率、修正事件处理和审计轨迹。司机能否公开显示姓名/评分也要符合隐私规则。

手动走一遍

司机 D 有 19 条五星评论,训练规则下尚未达到 20 条入榜门槛;第 20 条四星后进入所在城市榜单。若其中一条评分因申诉被撤销,sum/count 与索引同时更新,D 可能退出榜单。重复投递同一条撤销事件不能再次扣分。

规模与取舍

R 条事实评论占 O(R) 持久存储;每个有效评论/修正通常更新 O(1) 个时间桶和一个有序榜单键,索引更新约 O(log D),D 为分区内司机数。Top K 查询约 O(log D+K);任意窗口回扫成本随该窗口内评论数或桶数增长。

易错点与追问

容易失分的边界

  • 直接对评论表全量 group by 再排序作为每次榜单查询实现,热榜高 QPS 时成本随历史 R 增长。
  • 修改/撤销评论只更新原记录却不反向修正聚合,榜单和事实表永久不一致。
  • 一个五星评论排在几千条高分评论前,未讨论样本量偏差和产品排名政策。
  • 把司机评论榜单当作司机位置 heatmap,只谈空间格而不谈审核、时间窗和排名。

继续深挖

  • 如果按最近 7 天、30 天、历史总分同时查询,如何组织分层时间桶与增量索引?
  • 如何给每个名次提供可审计解释,尤其是评论撤销、风控过滤和地区归属变化?
  • 若榜单按平均分、接单率和取消率综合评分,权重怎样验证对司机和乘客都公平?
✓已复制微信号!