4

我的目标是生成一个类似于reddit首页的系统。

我有东西,为了简单起见,这些东西有投票权。我生成的最好的系统是使用时间衰减。7天半衰期,如果今天一票20分,7天后10分,14天后5分。

问题是,虽然这产生了我非常满意的结果,但它并没有扩展。每一次投票都需要我有效地重新计算每一次投票的价值。

所以,我想我也许可以扭转这个想法。今天的投票值 1 分。从现在起 7 天后的投票值 2 分,从现在起 14 天后的投票值 4 分,以此类推。这很有效,因为每次投票,我只需要更新一行。问题是,到今年年底,我需要一个可以容纳大量数字的数据类型。

所以,我尝试使用产生糟糕排名的线性增长。我尝试了多项式增长(将网站启动和提交后的天数平方和立方),它产生了稍微好一点的结果。然而,当我得到稍微好一点的结果时,我很快就会重新接近无法维护的数字。

所以,我来找你stackoverflow。谁有一个天才的想法或链接到如何对该系统建模以便它可以很好地扩展到 Web 应用程序的想法。

4

4 回答 4

2

我也一直在尝试这样做。我找到了一个看起来像解决方案的方法,但不幸的是,我忘记了如何做数学,所以我很难理解它。

这个想法是存储您的分数日志并按此排序,因此数字不会溢出。

该文档描述了数学。 https://docs.google.com/View?id=dg7jwgdn_8cd9bprdr

我发现它的评论在这里:http: //blog.notdot.net/2009/12/Most-popular-metrics-in-App-Engine#comment-25910828

于 2012-01-08T20:39:03.760 回答
0

好的,想到了一种解决方案,可以在每次投票时做到这一点。问题是它需要一个两边都有原子弹出/推送的链表来存储投票(例如 Redis 列表,但您可能不希望它在 RAM 中)。

它还要求衰减间隔是恒定的(例如 1 小时)

它是这样的:

  1. 在每次投票时,更新得分推送该投票的下一次衰减到列表的尾部
  2. 然后从列表的头部弹出第一票
  3. 如果它还不够老腐烂,把它推回头部
  4. 否则,从总分中减去所需的数量,并将更新的信息推送到尾部
  5. 从第 2 步开始重复,直到您获得足够新鲜的投票(第 3 步)

当然,您仍然必须检查后台的头像以清除没有人投票的帖子。

于 2012-01-06T07:16:49.197 回答
0

这里已经很晚了,所以我希望有人可以检查我的数学。我认为这相当于指数衰减。

MySQL 的 BIGINT 最大值为 2^64

为简单起见,让我们使用 1 天作为我们的时间间隔。设 n 为网站启动后的天数。

  1. 创建一个整数变量。让我们称它为 X 并从 0 开始
  2. 如果一个加法操作会带来超过 2^64 的分数,首先,通过将每个分数除以 2^n 来更新每个分数,然后设置 X 等于 n。
  3. 在每次投票中,将 2^(nX) 添加到分数。

所以,从心理上讲,这对我来说使用以 10 为底更有意义。当我们加起来时,我们的数字会越来越长。我们不再关心较低数字位置的数字,因为我们增加分数的值有很多数字。这意味着较低的数字停止计数非常多。因此,如果他们不计算,为什么不将小数位滑到我们关心的点,并在某个点截断小数位以下的数字。为此,我们还需要在每次添加的金额上滑动小数位。

我不禁觉得这有什么问题。

于 2012-01-06T07:36:29.197 回答
0

以下是您可以使用的两个可能的伪查询。我知道它们并没有真正解决可伸缩性问题,但我认为它们确实提供了方法,以便您可以

SELECT article.title AS title, SUM(vp.point) AS points
FROM article
LEFT JOIN (SELECT 1 / DATEDIFF(NOW(), vote.created_at) as point, article_id
  FROM vote GROUP BY article_id) AS vp  
ON vp.article_id = article.id

或(不是加入,我认为这会更快,但更难补充水分),

SELECT SUM(1 / DATEDIFF(NOW(), created_at)) AS points, article_id
FROM vote
WHERE article_id IN (...) GROUP BY article_id

这些查询的好处是它们可以随时使用相同的数据运行,并且它们将始终返回相同的答案。他们不会破坏任何数据。

如果需要,您还可以在后台作业中运行查询,它们仍然会给出相同的结果。

于 2012-01-06T17:27:50.530 回答