mysql - 带有加权分数的 Sql 流行度算法

标签 mysql sql algorithm popularity

鉴于他的好恶,我正在实现一种算法,该算法目前返回热门帖子。

为此,对于每个帖子,我添加他所有的喜欢 (1) 和不喜欢 (-1) 以获得他的分数,但每个喜欢/不喜欢都是加权的:最新的,最重的。例如,在用户喜欢帖子的那一刻,他的喜欢权重为 1。1 天后,它的权重为 0.95(如果不喜欢,则为 -0.95),2 天后,0.90,等等...... 21 天后达到 0.01。 (PS:这些都是近似值)

这是我的 table 的制作方法:

帖子表

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:我用的是TIMESTAMPDIFFMINUTE而不是 DAY直接因为我自己计算一天,否则它会返回一个整数,我想要一个浮点值,以便逐渐衰减加类而不是每天衰减。所以TIMESTAMPDIFF(MINUTE, Like.created, NOW())/60/24只是给我从小数部分创建以来经过的天数。

这是我的问题:
  • IF(expr1, expr2, expr3) part :有必要为同类的权重设置最小值,因此它不会低于 0.01 并变为负数(等等,甚至更老的权重仍然很小)。但我计算的是同一件事的 2 倍:expr1 与 expr2 相同。有没有办法避免这种重复的表达?
  • 我打算缓存这个查询并每 5 分钟更新一次,因为我认为它对一个大的 Post 来说会很重。和 Like table 。缓存真的有必要吗?我的目标是在具有 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 秒是 Not Acceptable )。

    最佳答案

    2: I was going to cache this query and update it every 5 minutes, as I think it will be pretty heavy on a big Post and Like table. Is the cache really necessary or not ? I'm aiming to run this query on a table with 50 000 entries, and for each 200 associated likes (that makes a 10 000 000 entries Like table).



    10000 和 50000 在当前硬件上被认为很小。使用这些表大小,您可能不需要任何缓存,除非查询每秒运行几次。
    无论如何,我会在决定使用缓存之前进行性能测试。

    3: Should I create Index in Like table for post_id ? And for created ?



    我会为(post_id,created,vote)创建一个索引。这样查询就可以从索引中获取所有信息,根本不需要读取表。

    编辑 (回复评论) :

    额外的索引会稍微减慢插入/更新速度。最后,您选择的路径将决定您在 CPU/RAM/磁盘 I/O 方面所需的特性。
    如果您有足够的 RAM 用于 DB,那么您期望整个 Like如果要缓存在 RAM 中的表,那么您最好只使用 post_id 上的索引.

    就总负载而言,您需要考虑 insert 之间的比率和 select以及使用或不使用索引的插入和选择的相对成本。
    我的直觉是总负载会随着索引而降低。

    关于您关于并发的问题(同时选择和插入)。发生什么取决于隔离级别。一般的建议是保持插入/更新尽可能短。如果您在 insert 开始之间不做不必要的事情和 commit你应该没事。

    关于mysql - 带有加权分数的 Sql 流行度算法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25374811/

    相关文章:

    PHP CodeIgniter - 关系表时如何获得好的结果数组(不同表中有相同的列名)

    java - BFS在关系数据库中的实现

    algorithm - 搜索列表

    ruby - 如何使用 ruby​​ 中的函数式编程范式在动态编程中重写查找最大连续子数组?

    mysql - MySQL显示多个表中的列

    php - 选择/使用该行条目后,标记表条目不再显示

    mysql - 如何在MySQL中创建更好的搜索查询

    sql - 如何编写 SQL 服务器数据库角色的脚本?

    mysql - SQL Case陈述式

    algorithm - A* 允许在网格上滚动的启发式算法