今日热门,本周,本月 – 设计模式
我有一个系统显示按三个字段之一排序的条目,最受欢迎的今天,本周和本月。 每次查看条目时,分数增加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
也许某种衰减可能会有所帮助。 Today
, Yesterday
, ThisWeek
, LastWeek
, ThisMonth
, LastMonth
你需要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
或衰减公式,以最好地满足您的需求。 这只是一个例子。