【发布时间】:2014-10-12 01:05:44
【问题描述】:
我正在实现一个算法,根据他的好恶返回当前的热门帖子。
为此,对于每个帖子,我添加他所有的喜欢 (1) 和不喜欢 (-1) 以获得他的分数,但每个喜欢/不喜欢都是加权的:最新的,最重的。例如,在用户喜欢帖子的那一刻,他的喜欢权重为 1。1 天后,它的权重为 0.95(如果不喜欢,则为 -0.95),2 天后,0.90,等等...... 21 天后达到 0.01。 (PS:这些都是近似值)
我的桌子是这样制作的:
帖子表
id | Title | user_id | ...
-------------------------------------------
1 | Random post | 10 | ...
2 | Another post | 36 | ...
n | ... | n | ...
点赞表
id | vote | post_id | user_id | created
----------------------------------------
1 | 1 | 2 | 10 | 2014-08-18 15:34:20
2 | -1 | 1 | 24 | 2014-08-15 18:54:12
3 | 1 | 2 | 54 | 2014-08-17 21:12:48
这是我目前正在使用的 SQL 查询完成这项工作
SELECT Post.*, Like.*,
SUM(Like.vote *
(1 - IF((TIMESTAMPDIFF(MINUTE, Like.created, NOW()) / 60 / 24) / 21 > 0.99, 0.99, (TIMESTAMPDIFF(MINUTE, Like.created, NOW()) / 60 / 24) / 21))
) AS score
FROM posts Post
LEFT JOIN likes Like ON (Post.id = Like.post_id)
GROUP BY Post.id
ORDER BY score DESC
PS:我直接使用TIMESTAMPDIFF 和MINUTE 而不是DAY,因为我自己计算日期,否则它会返回一个整数,我想要一个浮点值,以便逐渐衰减加班和不是每天一天。所以TIMESTAMPDIFF(MINUTE, Like.created, NOW())/60/24 只是给了我从小数部分创建以来经过的天数。
这是我的问题:
- 查看
IF(expr1, expr2, expr3)部分:有必要为like 的权重设置最小值,这样它就不会低于0.01 并变为负数(等等,甚至更老的还有一点权重)。但我计算的是同一件事的 2 倍:expr1 与 expr2 相同。有没有办法避免这种重复的表达方式? - 我打算缓存这个查询并每 5 分钟更新一次,因为我认为它在
Post和Like的大表上会非常繁重。缓存真的有必要吗?我的目标是在一个有 50 000 个条目的表上运行此查询,并且对于每 200 个关联的喜欢(这会产生一个 10 000 000 个条目Like表)。 - 我应该在
Like表中为 post_id 创建索引吗?而对于创造?
谢谢!
编辑: 想象一个Post 可以有多个标签,每个标签可以属于多个帖子。如果我想获得给定标签或多个标签的热门帖子,我无法缓存每个查询;因为有大量可能的查询。查询仍然可行吗?
编辑最终解决方案:我终于做了一些测试。我创建了一个包含 30 000 个条目的表 Post 和一个包含 250 000 个条目的 Like。 如果没有索引,查询会非常长(超时 > 1000 万),但在 Post.id (primary)、Like.id(primary) 和 Like.post_id 上的索引需要大约 0.5 秒。
所以我没有缓存数据,也没有每 500 万次使用更新。如果表不断增长,这仍然是可能的解决方案(超过 1 秒是不可接受的)。
【问题讨论】:
-
#1 - 在 MySQL 中,您可以使用 in-line 变量赋值。因此,您将第一次使用它,第二次使用该变量。
-
你能给我看看如何使用它的示例吗?
-
非常小的例子只是为了说明语法在this SQL Fiddle*中。
-
问题#2和#3更适合
DBAsite。 -
我知道这很简单。但是如何在聚合函数中使用它?我不能直接把它放在 SUM 中。否则,它只返回第一行(第一个关联的like)的结果(权重)。
标签: mysql sql algorithm popularity