#source code
cdef extern from "math.h":
double log10(double)
double sqrt(double)
epoch = datetime(1970, 1, 1, tzinfo = g.tz)
cpdef double epoch_seconds(date):
"""Returns the number of seconds from the epoch to date. Should
match the number returned by the equivalent function in
postgres."""
td = date - epoch
return td.days * 86400 + td.seconds + (float(td.microseconds) / 1000000)
cpdef long score(long ups, long downs):
return ups - downs
cpdef double hot(long ups, long downs, date):
return _hot(ups, downs, epoch_seconds(date))
cpdef double _hot(long ups, long downs, double date):
"""The hot formula. Should match the equivalent function in postgres."""
s = score(ups, downs)
order = log10(max(abs(s), 1))
if s > 0:
sign = 1
elif s < 0:
sign = -1
else:
sign = 0
seconds = date - 1134028003
return round(sign * order + seconds / 45000, 7)
#analysis
cdef extern from "math.h":
double log10(double)
double sqrt(double)
从外部(math.h)引入两个数学函数
epoch = datetime(1970, 1, 1, tzinfo = g.tz)
定义时间基准为UTC标准起始时间
cpdef double epoch_seconds(date):
"""Returns the number of seconds from the epoch to date. Should
match the number returned by the equivalent function in
postgres."""
td = date - epoch
return td.days * 86400 + td.seconds + (float(td.microseconds) / 1000000)
如代码中注释所示,返回从时间纪元起始到给定时间的秒数 td为两个时间对象相减产生的时间间隔(timedelta)对象,时间间隔对象只在内部存储: 天 , 秒 , 微秒 . 其中:86400 表示一天(24小时)的总秒数,微秒为百万分之一秒。
cpdef long score(long ups, long downs):
return ups - downs
返回赞同数与反对数的差值
cpdef double hot(long ups, long downs, date):
return _hot(ups, downs, epoch_seconds(date))
计算热度的 major method ,接收三个参数:赞同数、反对数、当前时间(内部通过调用
epoch_seconds
方法将当前时间换算为距离时间纪元的秒数)
cpdef double _hot(long ups, long downs, double date):
"""The hot formula. Should match the equivalent function in postgres."""
s = score(ups, downs)
order = log10(max(abs(s), 1))
if s > 0:
sign = 1
elif s < 0:
sign = -1
else:
sign = 0
seconds = date - 1134028003
return round(sign * order + seconds / 45000, 7)
计算热度的公式,其中:
s :得分,赞同数与反对数的差值
order :分解如下
abs(s) :得分的绝对值,忽略正负,下面简称为 x
max(x,1) :如果赞同数等于反对数,则结果为1,否则为x,对其结果下面简称为 y
log10(y) :此处为什么要选择进行log运算,目的是为了 平缓 跟风投票/后续投票的 影响力 (有些权重的意思) ,例如此处y为1,结果为0;y为10,结果为1;y为100,结果为2;y为1000,结果为3;投前10票的人,跟后面跟风投99票的人影响力等同。这在某种程度上对恶意刷排名有一定的抑制作用。对于该结果,下面简称为 z
sign :是一个标识,用于判断,该帖子的整体的趋势是被赞成还是被反对的,它很重要,因为在下面它直接决定了,它是评判热度的加分项还是减分项!
seconds :得出发帖时间,上面已经提到,这里的date变量存储的是发帖时间距离时间纪元的秒数,而此处的 1134028003 换算成日期时间为: 2005年12月8日7:46:43 对于该特殊时间的解释,网传是Reddit成立的时间,由此可见,seconds又是个相对时间的秒数,可以理解为相对发帖时间
round(sign * order + seconds / 45000, 7) :分解如下
sign * order :根据赞成数与反对数来计算得分,上面以及解释过,两者的差额越大,则order越高。但光凭差额还不够,需要看用户的投票趋势或方向(这是非常重要的)。因此sign直接影响热度(如果用户整体呈反对趋势,不认为它热度很高)。
seconds / 45000 :表示发帖时间越长,其排名越往下降,45000为12.5小时的秒数(即为半天),注意,seconds是一个相对时间,如果发帖时间越早,其越小,导致该值也就越小
round(sign * order + seconds / 45000, 7) :保留小数点后的7位
总结:Reddit上帖子的热度,主要依赖两个指标:赞成与反对的投票方向与投票差、发帖时间的早晚。这是Reddit帖子热度计算的最新公式,而之前的公式是:查看commit
round(order + sign * seconds /45000, 7)
可以看出就在前不久提交的修改,提交人员给出的comment为: Make hot score continuous. 从修改中,确实可以看出,这是为了保持帖子在同一投票方向以及时间上的连续性。 sign 原本就是根据赞同/反对得出的投票方向,应该将其的影响施加在跟投票相关的评比项上,而不应该跟影响到时间的评比。
源码地址:https://github.com/reddit/reddit/blob/master/r2/r2/lib/db/_sorts.pyx