今日热门,本周,本月 – 设计模式

我有一个系统显示按三个字段之一排序的条目,最受欢迎的今天,本周和本月。 每次查看条目时,分数增加1,从而改变顺序。

因此,如果条目1是新的并且今天被观看10次,其分数将是:

Today: 10 Week: 10 Month: 10 

当前的解决方案

目前我只有3个与每个条目相关联的字段,一个用于本周的另一个用于本周,另一个用于本月。 每次查看条目时,所有三个分数都会增加1。

在一天结束时,将日分数重置为0.在当前周结束时,将周分数设置为0,并且在当前日历月结束时,将月分数设置为0。

问题

虽然这种方法有用并占用空间很小,但由于两个原因,它并不理想:

1)在当前时段(日,周,月)结束时,该值一次性重置为0,这意味着每天00:00:00排名全部重置,所有每日分数都设置为0,在本周末和月末也是如此。 在每个月1日的00:00:00,所有分数被设置为0,从而丢失所有现有的排名数据。

2)因为月末通常在一周内(周一至周日),所以每周的分数在一周内被重置,导致每周分数高于每月分数。

可能解决方案

我可以使用每小时每小时的滚动小时计数器,用于根据当前小时指数计算当前日,周,月的分数。

 Array size = 31 * 24 = 744 int16 values 

所以在1日凌晨4点,视图将在几个小时内放置[4]

 hours[4]++ 

然后,统计计算器将使用今天作为最后24个值的总和,并且本周分数将是最后(24 * 7)值的总和。 最后,本月将是最后(24 * 31)值的总和。

解决问题

解决方案1的主要问题是磁盘/内存要求。 我已经从当前解决方案中的3个32位值变为使用744个32位值。 即使我将它们改为in16,我仍然会在每个条目中使用更多的内存

 Memory per Entry = 3 * 4 bytes = 12 bytes (Existing) Memory per Entry = 744 * 2 = 1,488 bytes (possible solution) 

有了这个解决方案,我的每个条目的内存使用率已经跃升了12400%!!

任何人都可以提出另一种解决方案,以解决当前解决方案中的问题,但每次使用不会使用1.5k?

非常感谢!

这实际上是如何有效地分组数据并保留所有必要信息的常见问题。

首先:你尝试过自己的方式吗? 你真的缺少存储吗? 您的解决方案似乎合理

我该怎么做

我假设您使用数据库来保存数据。

我会创建两个单独的表,一个用于hourly ,一个用于daily统计。 每篇文章在该数据库中只有24行,每小时一行。 这将用于hourly统计。 要更新特定行,您只需要知道小时(0-23)和entry_id。 UPDATE count=count+1 WHERE hour=11 AND entry_id = 18164;

 entry_id foreign key | hour integer | count integer ---------------------+--------------+-------------- 1 | 0 | 123 1 | 2 | 1712 ... 

当前的每日统计数据将在午夜(或应用程序最少)或按需求总和时计算。 无论哪种方式,每天一次,必须对所有小时数据进行求和,并且必须将总和插入daily统计表中。

 entry_id foreign key | day date | count integer ---------------------+------------+-------------- 1 | 2013-07-03 | 54197 1 | 2013-07-04 | 66123 ... 

超过31(30/29/28)天的每个条目都应删除。 或者,如果您想要全部或年度统计数据

好处

  • 您保存的数据少于完整的每小时统计数据:24 + 31
  • 如果在entry_id和hour上编入索引,则每小时表的总和应该很快
  • 使用的内存少于解决方案

缺点

  • 每日更新统计信息所需的其他脚本/触发器/作业
  • 实现它需要比解决方案更多的工作

一个简单的解决方案是

 Use an array of 31. Today - the last value This Week score would be the sum of the last 7 values. This Month would be the sum of the last 31 values. At the end of each day, shift the whole array values by 1 to accommodate new value. 

关于你的评论,

 Use another array of size 24 to store hours visit count. Today - Sum of all elements of Array2 This Week score would be the sum of the last 7 values of Array1. This Month would be the Sum of all elements of Array1. At the end of each day, shift the whole array values of Array1 by 1 to accommodate new value. Last day visit count = Sum of all elements of Array2 

也许某种衰减可能会有所帮助。 TodayYesterdayThisWeekLastWeekThisMonthLastMonth你需要6个变量。

然后最终评级(例如每日)可以被计算为: Today + Yesterday * attenuation( current_time - start_of_the_day )

衰减类似于1 / (1 + k * time) ,其中k是可调节的,具体取决于您希望最后一天评级放气的速度。

更新:考虑在一天内查看123次新条目。 让我们以秒为单位测量时间,以获得一些数字。 在23:59,etrys的评级为123 + 0 * 1 / (1 + k * 86340)^2 = 100

午夜Today柜台成为Yesterday

 0 + 123 * 1 / ( 1 + k * 0)^2 = 123 

假设在中午之前,一个条目获得了89多个观看次数。

 89 + 123 * 1 / ( 1 + k * 43200 )^2 = ? 

那么,现在是选择k的好时机。 如果我们希望旧视图在12小时内淡出四次,则k将为1/43200 。 如果我们想要衰落一百次 – 9/43200 。 在这种情况下:

 89 + 123 * 1 / ( 1 + 9 )^2 = 90.23 

然后到23:59。 让条目获得60多个视图

 149 + 123 * 1 / ( 1 + (9/43200) * 86340 )^2 ~= 149.002 

所以昨天的观点几乎完全失去了他们对24小时评级的影响。 当然,您可以使用k或衰减公式,以最好地满足您的需求。 这只是一个例子。