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

时间:2013-07-04 09:01:47

标签: c# algorithm design-patterns

我有一个系统显示按三个字段之一排序的条目,最受欢迎的今天,本周和本月。每次查看条目时,分数将增加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吗?

非常感谢!

3 个答案:

答案 0 :(得分:6)

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

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

我该怎么做

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

我会创建两个单独的表,一个用于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和小时
  • 上编入索引
  • 使用的内存少于解决方案

<强>缺点

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

答案 1 :(得分:2)

一个简单的解决方案是

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

答案 2 :(得分:2)

也许某种衰减可能会有所帮助。 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或衰减公式,以最好地满足您的需求。这只是一个例子。