Hacker News 的排名到底怎么算:打分、争议与降权
作者连续几天抓取 HN 前 60 名做逆向分析:公开公式基本准确,但首页有 20% 的文章被降权;标题含 NSA 一律乘 0.4;评论多于票数且达到 40 条会触发「争议」惩罚,让文章瞬间从首页消失。
中文
复制

Hacker News 排名的基本公式多年前就已公开,但一些问题仍未解答:公开的代码是否就是真实算法?排名纯粹由投票决定,还是有看不见的因素在起作用?关于 NSA 的文章会被压下去吗?为什么那篇热门文章在你评论之后突然从首页消失了?
通过连续几天仔细分析 HN 排名前 60 的文章,我可以回答这些问题以及更多。公开的公式大体是准确的。排名上的调整远比你想象的多:20% 的首页文章以各种方式被降权。 标题里带「NSA」的任何内容都会被降权并迅速掉下去。一篇「有争议」的文章在评论数达到 40 后会被严厉降权。本文详细描述打分与降权机制。(编者注:HN 后来不再对 NSA 文章降权,详见。)
文章得分基于其得票数、提交至今的时间以及各种惩罚因子,公式为:
score = (votes - 1)^0.8 / (age_hours + 2)^1.8 × penalties
由于时间的指数大于票数的指数,一篇文章的得分最终会降到零,所以没有什么能长期留在首页。这个指数被称为重力(gravity)。
你可能会以为,每次你访问 Hacker News 时,所有文章都会用上面的公式重新算分并排序以确定名次。但为了效率,单篇文章只会偶尔被重新排名。当一篇文章被投票时,它会被重新排名并移动到列表中合适的位置,而其他文章保持不变。因此重新排名的总量大幅减少。但这带来一种可能:一篇文章停止获得投票,却卡在高位上。为避免这种情况,每隔 30 秒会从排名前 50 的文章中随机挑一篇重新排名。后果是:如果不涨票,一篇文章可能在很多分钟里处在「错误」的名次上。此外,页面可以被缓存 90 秒。
原始分数与某一天的第 1 名
下图显示 11 月 11 日一整天的 HN 前 60 篇文章的原始分数(不含惩罚)。每条线对应一篇文章,颜色按其页面位置区分。红线是 HN 的置顶文章。注意:由于惩罚的存在,原始分最高的文章常常并不是置顶的那篇。

这张图透露了几件有意思的事。一篇文章的分数会迅速冲高,然后在许多小时里缓慢下降。打分公式解释了其中大部分:一篇以恒定速率获得投票的文章会快速到达峰值,随后逐渐下滑。但实际观察到的峰值更快——这是因为文章往往在最初一两个小时内获得大量投票,之后投票速率下降。两个因素叠加,就得到图上那种陡峭曲线。
每天都有几篇文章的分数远高于其余,同时有大量文章位于中段。有些文章得分很好,但运气不佳,被更热门的文章压在后面。另一些文章则在某篇下滑、另一篇上升的间隙里短暂登顶。
比较「原始分最高的文章」(图的顶端)与「排名最高的文章」(红线)之间的差距,就能看出惩罚在何时被施加。文章《把网站注册彻底做错》在清早登上第 1 名,但因「有争议」被降权,迅速从页面上掉下去,让《Linux 吃掉了我的内存》短暂拿到第 1 名,随后被《用 CSS 画辛普森一家》超过。稍后,Apple Maps刚刚登上第 1 名就被施加争议惩罚,于是丢掉第 1 名并迅速下坠。Snapchat那篇曾到达 HN 顶端,但在上午 8:22 被降权得太狠,直接从榜单上消失。《你为什么绝不该用 MongoDB》极受欢迎,本可以在当天大部分时间占据第 1 名,却被迅速降权,在第 7 名附近徘徊。《与 NSA 断绝关系》一开始就吃了 NSA 惩罚,但因为太热门,仍然拿到了第 1 名;然而它很快被施以更重的惩罚,被压到页面下方。最后,临近当天结束时,《410 万美元失踪》被降权——而事实证明,即使没有惩罚,它也会很快把第 1 名让给 FTL。
绿色三角与文字标出「争议」惩罚在哪被施加。蓝色三角与文字标出文章被降权到彻底消失、跌出前 60 的位置。较轻的惩罚没有在这里标出。
很明显,HN 第 1 名的内容并不是「自然」形成的,而是对许多文章不断施加惩罚的结果。这些惩罚来自 HN 管理员,还是来自文章被 flag,目前并不清楚。
会被自动降权的提交
有些提交因为标题被自动降权,另一些因为域名被降权。看起来任何标题里含 NSA 的文章都会自动得到 0.4 的惩罚。我找过其他会引发自动惩罚的词,例如 awesome、bitcoin、bubble,它们似乎不会被降权。我观察到许多网站似乎会自动获得 0.25 到 0.8 的惩罚:arstechnica.com、businessinsider.com、easypost.com、github.com、imgur.com、medium.com、quora.com、qz.com、reddit.com、rt.com、stackexchange.com、theguardian.com、theregister.com、theverge.com、torrentfreak.com、youtube.com。我确信实际清单更长。(这与「被封禁」的站点是两回事,后者曾被列出过。)
eterm 提出的一个有意思的理论是:来自热门来源的新闻会被多个人并行提交,从而获得超过文章「应得」的票数。对热门网站自动降权有助于抵消这种效应。
惩罚的影响
用打分公式可以算出惩罚的影响。如果一篇文章的惩罚因子是 0.4,这等价于每张票只算 0.3 票;换一种说法,它的排名下降速度比正常快 66%。惩罚因子为 0.1 则相当于每票只算 0.05 票,或者说文章以正常速度的 3.6 倍下坠。因此 0.4 的惩罚影响显著,而 0.1 非常严厉。
争议。 为避免 Hacker News 上出现骂战,评论「过多」的文章会被当作「有争议」而严厉降权。在公开代码里,contro-factor 函数对任何评论数超过 20、且评论多于得票的帖子生效,这类文章会按 (votes/comments)^2 缩放。但真实公式不同:它对任何评论多于得票、且评论数至少 40 的帖子生效。根据经验数据,我怀疑指数是 3 而不是 2,但没有证实。争议惩罚能对文章排名产生突然而灾难性的影响,让一篇文章前一分钟还排名很高,一撞到 40 条评论就消失。如果你曾疑惑某篇热门文章为何突然从首页消失,争议很可能是原因。例如《为什么 Chromebook 的评论家们脱离现实》在评论数达到 40 的那一刻从第 5 名掉到第 22 名,而 Show HN:从任何医生那里拿到你的健康记录原本在第 17 名,在达到 40 条评论时从前 60 名中彻底消失。
我的方法
我每分钟抓取一次 /news 与 /news2 页面(保持在每分钟 2 页的建议上限之内)。我用 Beautiful Soup 解析(有点丑的)HTML,用一大堆 Python 脚本处理结果,并用难懂但强大的 matplotlib 画图。分析的基本思路是:用公式算出原始分,然后寻找异常。在某个时刻(例如 11/09 8:46),我们可以算出前 10 篇文章的原始分:
2.802 Pyret: A new programming language from the creators of Racket
1.407 The Big Data Brain Drain: Why Science is in Trouble
1.649 The NY Times endorsed a secretive trade agreement that the public can't read
0.785 S.F. programmers build alternative to HealthCare.gov (warning: autoplay video)
0.844 Marelle: logic programming for devops
0.738 Sprite Lamp
0.714 Why Teenagers Are Fleeing Facebook
0.659 NodeKnockout is in Full Tilt. Checkout some demos
0.805 ISO 1
0.483 Shopify accepts Bitcoin.
0.452 Show HN: Understand closures
注意前 10 名中有三篇(The NY Times、Marelle、ISO 1)的排名低于其分数所暗示的位置。由于 The NY Times 排在 1.407 与 0.785 的文章之间,它的惩罚因子可以推算在 0.47 到 0.85 之间。同理,另两篇的惩罚必须在 0.87–0.93 与 0.60–0.82 之间。我观察到大多数文章都按分数排名,而例外者总是排名低得多,说明存在惩罚。这也说明在用的打分公式与公开代码一致。如果公式不同——比如重力指数更大——我预期会看到文章随着票数或时间增长而逐渐偏离其「应得」名次,但我从未观察到这种情况。
这个技巧能证明惩罚存在并给出区间,但要确定精确的惩罚值很难。你可以观察区间随时间的变化,希望它收敛到单一数值。然而有几种误差来源会干扰:第一,相邻文章也可能被惩罚,或计分方式不同(比如招聘帖);第二,因为文章不是一直被重新排名,某篇可能暂时不在应在的位置;第三,惩罚值可能随时间变化;第四,显示的票数可能与实际票数不同,因为「坏」票会被抑制。结果是:我只能确定大致的惩罚值,数值上有相当大的不稳定性。
一天中的惩罚
下图显示一天中推算出的惩罚值。每条线代表一篇文章,应从 1(无惩罚)开始,在被施加惩罚时下降到某个水平。线条在该文章跌出前 60 时结束——而这可能发生在惩罚施加后不久。看起来存在 0.2 与 0.4 的惩罚,以及大量落在 0.8–0.9 区间的惩罚。似乎很多惩罚在上午 9 点被施加(管理员到岗?),之后全天还有更多。我仍在试验不同算法来改进这张图,因为它相当嘈杂。

平均而言,首页约 20% 的文章被降权过,而第二页有 38% 被降权过。(首页的比例较低,因为被降权的文章按定义更不容易待在首页。)降权发生的程度远超你的想象。
以下是 11/11 首页上被降权的文章清单。(这不包括那些本来会在首页、但因被降权而没上的文章。)这份清单比我预想的长得多;完整列表请滚动查看。
Why the Climate Corporation Sold Itself to Monsanto、Facebook Publications、Bill Gates: What I Learned in the Fight Against Polio、McCain says NSA chief Keith Alexander 'should resign or be fired'、You are not a software engineer、What is a y-combinator?、Typhoon Haiyan kills 10,000 in Philippines、To Persuade People, Tell Them a Story、Tetris and The Power Of CSS、Microsoft Research Publications、Moscow subway sells free tickets for 30 sit-ups、The secret world of cargo ships、These weeks in Rust、Empty-Stomach Intelligence、Getting website registration completely wrong、The Six Most Common Species Of Code、Amazon to Begin Sunday Deliveries, With Post Office's Help、Linux ate my RAM、Simpsons in CSS、Apple maps: how Google lost when everyone thought it had won、Docker and Go: why did we decide to write Docker in Go?、Amazon Code Ninjas、Last Doolittle Raiders make final toast、Linux Voice - A new Linux magazine that gives back、Want to download anime? Just made a program for that、Commit 15 minutes to explain to a stranger why you love your job.、Why You Should Never Use MongoDB、Show HN: SketchDeck - build slides faster、Zero to Peanut Butter Docker Time in 78 Seconds、NSA's Surveillance Powers Extend Far Beyond Counterterrorism、How Sentry's Open Source Service Was Born、Real World OCaml、Show HN: Get your health records from any doctor、Why the Chromebook pundits are out of touch with reality、Towards a More Modular Future for JavaScript Libraries、Why is virt-builder written in OCaml?、IOS: End of an Era、The craziest things you can plug into your iPhone's audio jack、RFC: Replace Java with Go in default languages、Show HN: Find your health plan on Health Sherpa、Web Latency Benchmark: A new kind of browser benchmark、Why are Amazon, Facebook and Yahoo copying Microsoft's stack ranking system?、Severing Ties with the NSA、Doctor performs surgery using Google Glass、Duplicity + S3: Easy, cheap, encrypted, automated full-disk backups、Bitcoin's UK future looks bleak、Amazon Redshift's New Features、You're only getting the nice feedback、Software is Easy, Hardware is of Medium Difficulty、Facebook Warns Users After Adobe Breach、International Space Station Infected With USB Stick Malware、Tidbit: Client-Side Bitcoin Mining、Go: "I have already used the name for MY programming language"、Multi-Modal Drone: Fly, Swim & Drive、The Daily Go Programming Newspaper、"We have no food, we need water and other things to survive."、Introducing the Humble Store、The Six Most Common Species Of Code、$4.1m goes missing as Chinese bitcoin trading platform GBL vanishes、Could Bitcoin Be More Disruptive than the Internet?、Apple Store is updating。
打分公式的代码
某个版本的 HN 服务端 Arc 源码可以获取,另有一份更新过的打分公式:
(= gravity* 1.8 timebase* 120 front-threshold* 1
nourl-factor* .4 lightweight-factor* .17 gag-factor* .1)
(def frontpage-rank (s (o scorefn realscore) (o gravity gravity*))
(* (/ (let base (- (scorefn s) 1)
(if (> base 0) (expt base .8) base))
(expt (/ (+ (item-age s) timebase*) 60) gravity))
(if (no (in s!type 'story 'poll)) .8
(blank s!url) nourl-factor*
(mem 'bury s!keys) .001
(* (contro-factor s)
(if (mem 'gag s!keys)
gag-factor*
(lightweight s)
lightweight-factor*
1)))))
如果你不读 Arc 代码:上面这段定义了几个常量——gravity* = 1.8、timebase* = 120(分钟)等。然后它定义了一个方法 frontpage-rank,依据文章 s 的得票(realscore)与以分钟计的年龄(item-age)来排名。惩罚因子由一个多分支的 if 定义:如果文章不是 'story' 或 'poll',因子为 0.8;否则,如果 URL 字段为空(Ask HN 之类),因子为 nourl-factor*;如果文章被标记为 'bury',缩放因子是 0.001,文章被排到九霄云外;最后默认分支组合了争议因子与 gag/lightweight 因子。争议因子 contro-factor 意在压制那些引发骂战的帖子,稍后我们会讨论更多。
下一个因子会给被标记为 gag(玩笑)的文章以 0.1 的重罚,给「轻量级」文章 0.17 的因子。实际的惩罚体系看起来比公开代码里呈现的要复杂得多。
结论
一篇文章在 Hacker News 首页上的位置,并不是你想象的「按票数论功行赏」的精英制。通过仔细考察出现在 HN 页面上的文章,我们可以对在用的打分公式了解很多。虽然得票是控制排名的显性因素,但还存在一套复杂的「惩罚」体系,会让文章排名更低、甚至彻底消失。这不仅仅是在防垃圾信息,而是影响到许多非常热门的文章。而且,如果一篇文章的评论数多于票数,别去给它加评论,否则你可能把它直接干掉!详见 Hacker News 上的讨论。
更新(11/18):讲惩罚的文章自己被惩罚了
讽刺的是,这篇文章在 Hacker News 上被降权了。它登上首页几分钟后,一条 0.2 的重罚就被施加到它身上,把它挤下首页。下图中的黑线显示本文在 Hacker News 上的位置:你可以看到惩罚施加时那条陡降。灰线显示如果没有惩罚,这篇文章会排在什么位置——没有惩罚的话它本可以到第 5 名,但有了惩罚,它始终没能回到首页(1–30 名)。下面那条绿线是本文的原始分。(11/26:有人告诉我,惩罚是因为「投票环检测」被误触发。)

来源: righto.com← 返回首页