!

This page is not translated yet

The interface, navigation and community content are bilingual. The long-form body of this page is still in Chinese. The translation work is tracked as task I18N-10.

See translation tasks

Module 04 · V1.0 · Voting & Ranking

投票与排序算法

社区的心跳,用算法替代人工编辑分发

P0V1.0缺失则产品不成立,必须最先交付

模块目标

要达成什么

实现幂等、可撤销、可加权、抗刷的投票系统,并把票数与时间衰减合成排序分数,驱动所有信息流的排序。

为什么必须存在

排序决定了什么内容被看见,而「被看见」直接决定创作者的激励。这是社区产品最核心的杠杆,必须最早做对。

功能清单

共 8 个功能点,每个功能点给出实现要点,可直接作为开发任务的描述。

上下投票(Upvote / Downvote)

P0

对帖子与评论均可投票,支持投票、取消、切换方向三种状态。

实现要点:voting 表用 (user_id, target_type, target_id) 唯一索引,value ∈ {1, -1};重复请求幂等返回。前端乐观更新,服务端返回权威计数。

Hot 热度排序

P0

综合票数与时间的排序公式,保证新鲜内容有机会超越老内容。

实现要点:score = log10(max(|v|,1)) × sign(v) + age_seconds / 45000。对数项压缩票数差距(1 票与 1000 票不至于天差地别),第二项随时间线性增长,约 12.5 小时抵消一个数量级的票数差。

多档排序策略

P0

Hot(热度)、New(最新)、Top(最高分,支持 小时/天/周/月/年/全部 时间窗)、Rising(上升中)、Controversial(争议)。

实现要点:Hot/New 走 Redis ZSet 直接取;Top 按时间窗在数据库按分数排序(有覆盖索引);Controversial 按 min(up, down) 且 up 与 down 接近度排序;Rising 用近期票速度(票数 / 时间)排序。

投票权重与降权

P1

依据信任等级与 Karma 加权;可疑账号的票权重降为 0(仍记录但不计分)。

实现要点:权重表按 trust_level 映射(TL0=0、TL1=0.5、TL2=1、TL3=1.5、TL4=2)。反作弊服务命中则把该用户近期所有票标记为 weight=0 并触发分数重算。

评论独立排序

P1

评论可选择「最佳(Best)」「最新(New)」「争议(Controversial)」「最旧(Old)」四种排序,并记忆用户偏好。

实现要点:排序偏好写入 user_settings,服务端在返回评论树时按偏好组装顺序;每个层级应用相同的排序策略(保持树结构的语义一致)。

分数预计算与缓存

P0

热度分数写入 Redis 有序集合 + 数据库快照,避免每次请求实时聚合。

实现要点:投票后异步重算该条目的 hot_score 并 ZADD;定时任务(每 10 分钟)批量重算近期内容,防止时间项长期未更新导致排序失真。

反刷票机制

P1

设备指纹、IP 聚集、注册时间、行为序列、投票图聚类的多层检测。

实现要点:规则层拦截明显异常(同 IP 多账号互相投票),模型层对投票关系图做社区发现,识别互投团伙并整体降权。

票数展示策略

P2

可配置为精确展示、模糊展示(1.2k)、或发布初期隐藏票数(防止从众效应)。

实现要点:隐藏期内仅作者可见真实票数;展示时统一使用紧凑格式,避免长数字撑破布局。

交互设计

2 条关键交互的分步流程,按用户体验顺序描述,可直接作为前端开发与可用性测试脚本。

1

投票交互

  1. 1

    点击向上箭头,立即变为主色高亮、计数 +1,进入乐观状态。

  2. 2

    再次点击同一箭头则取消投票,计数回落,按钮恢复灰色。

  3. 3

    点击向下箭头则切换为反对,计数从 +1 变为 -1(净变化 -2)。

  4. 4

    服务端返回后静默校正;若失败则回滚并有轻微抖动动画提示。

  5. 5

    未登录用户点击投票弹出登录引导,登录后自动补投该次投票。

2

切换排序

  1. 1

    列表顶部 Tab 切换 Hot / New / Top,切换时保留滚动位置的比例而非绝对像素。

  2. 2

    选择 Top 时展开时间窗下拉(今天/本周/本月/今年/全部)。

  3. 3

    排序偏好写入本地与账号,下次进入自动应用。

业务规则

6 条硬性约束。这些规则应当在服务层强校验,而非仅在前端提示。

R01

一个用户对同一目标只能有一个有效投票记录。

R02

投票可撤销,撤销后不得计入任何统计。

R03

帖子发布后 1 小时内禁止作者对自己的帖子投票(自投无效,直接忽略)。

R04

同一 IP 24 小时内对同一目标的多账号投票只计一次。

R05

Hot 分数中时间项每 45000 秒累计 1 分,约 12.5 小时抵消 10 倍票数差。

R06

投票计数与 Karma 更新允许最终一致,但用户自身的票状态必须强一致(读己之写)。

排序策略对照

Hot 热度log10 票数 + 时间衰减首页默认、社区默认兼顾质量与新度
New 最新created_at DESC追新用户、突发事件绝对时序,零延迟
Top 最高分score DESC(时间窗过滤)精华回顾、周报需要时间窗限定
Rising 上升近期票速度发现早期优质内容需滑动窗口计数
Controversial 争议up 与 down 接近且总数高争议话题、辩论需双向票数据

涉及数据表

本模块涉及的 6 张表。完整字段、索引与说明见「数据表设计」页。

竞品参考

本模块的设计参照了哪些产品,具体参照了什么。

RE

Reddit

Hot 公式的经典实现,对数压缩 + 时间衰减。

HA

Hacker News

Score = (v-1)/(age+2)^1.8,更激进的时间衰减。

LO

Lobsters

低 Karma 用户投票权被削弱,隐性降权值得借鉴。

LE

Lemmy

物化视图预计算排序分数,读取性能优异。

验收指标

本模块交付时应当达到的量化目标。未达标即视为该模块未完成。

投票接口 P95≤ 80ms
投票参与率浏览 → 投票 ≥ 8%
榜单第 1 页平均新鲜度Hot 榜首屏内容中位年龄 ≤ 8 小时
刷票识别率≥ 95%,误伤率 ≤ 1%

避坑清单

竞品踩过的坑,以及本模块在实现时最容易犯的错误。

  • 不要用单独的 upvote_count 字段做排序输入,必须把时间项写进分数,否则老内容永久霸榜。

  • 投票计数用 COUNT(*) 实时统计会在热门帖上打爆数据库,必须走增量计数器。

  • 排序分数若长期不重算,时间项会失真,必须定时回填。

  • 前端乐观更新必须有回滚路径,否则网络抖动会造成数据与现实不符。