2012-02-15 203 views
2

我昨天问了一个关于SO的问题,标题为Deciding and implementing a trending algorithm in Django。很多人提出了一个简单的事情,像平均值(指数,权重等) 我有一本名为模型和另一个叫读者:计算和存储每日,每周,每月和每年的平均数据

class Book(models.Model): 
    name = models.charField() 

class Reader(models.Model): 
    date = models.DateField() 
    book = models.ForeignKey(Book) 
    reader_count = models.PostiveIntegerField() 

结构简单。每天都会添加新书,并且每天都会添加每本书的读者数量。即一本书将有一天的读者数量为每天,多个记录。

我需要计算本周,当前月份和当年的图书平均值。除了目前的数据,我还想保留历史数据。

如果我试图从数据库中查询这种数据,那就需要大打了。不是吗。此外,我试图用简单的平均数来实现这个系统,但是后来我想要改变我的计算方法的灵活性。我有两个选择 -

  • 之一,在那里我可以在部分每次添加新Reader创纪录的时间存储的运算数据的另一个表更新数据。

  • 二,在那里我可以每天晚上通过脚本为当前日/周/月重建汇总数据。

下面是一些示例数据和结果。

Book Date  Count 
---- ---------- ----- 
AAAA 01.01.2012 10 
AAAA 02.01.2012 20 
AAAA 03.01.2012 30 
AAAA 04.01.2012 30 
AAAA 05.01.2012 40 
AAAA 06.01.2012 10 
AAAA 07.01.2012 25 
AAAA 08.01.2012 15 
AAAA 09.01.2012 10 

第1周的读者人数平均值为:23.5。 第2周的平均读者数(本例将为当周)为:12.5 ..并且当前月份和年份为21.1

HTH。

为了给任何一个镜头,我想建立一个系统来存储数据。我需要每天,每周和每月存储平均值。然而,我很遗憾我应该实现什么样的表结构?如果可能的话,我不想重新发明轮子,所以如果你们中的任何一个知道任何允许我实现这个目标的软件包,那将是非常棒的。

谢谢。

回答

1

我开始django-cube来处理这种类型的问题(请参阅维基百科上的OLAP cube)。然而,由于时间不够,我没有设法得到一个适当的,有效的版本...所以不幸的是它不会在你的情况下。

因为很多人一直在问我关于django-cube,我开始重新开发,在一个新的存储库on github。我现在对这个问题的经验比两年前(当我第一次尝试时)有更多的经验,所以我对我必须做什么以及API应该是什么样子有一个很好的想法;当我有空时,我会慢慢发展它。敬请期待,当然对这个项目的任何帮助都会非常受欢迎。

+0

谢谢你的回复塞巴斯蒂安。 – 2012-02-16 15:10:38

+0

不客气...对不起,我忍不住了! – sebpiq 2012-02-16 15:12:02

2

Postgres非常擅长与其他流量同时进行这些计算,因此不必太担心加载(只要您在请求 - 响应周期之外运行此类批处理作业)。

你可能看到的一件事是将这种工作分解成小缓存单元。即一个月的平均值实际上是过去4周的平均值,一年的平均值是过去12个月的平均值,而且这些都是以每本书的基础完成的,所以为什么不做小的子集在请求中的工作。

from django.core.cache import cache 
from datetime import timedelta 

def cached(key, expire) 
    def wrapped(f): 
     def func(*args, **kwargs): 
      result = cache.get(key%args%kwargs) 
      if result is None: 
       result = f(*args, **kwargs) 
       cache.set(key%args%kwargs, result, expire) 
      return result 
     return func 
    return wrapped 

@cached("book:%s:avg:week:%s", 3600*24) #cache for a day, rolling results! 
def book_read_week_average(book_id, week_start): 
    week_end = week_start + timedelta(days=7) 
    return Reader.objects.filter(book_id=book_id, date_gte=week_start, date_lt=week_end) \ 
         .aggregate(Avg('count'))['count_avg'] 

@cached("book:%s:avg:month:%s", 3600*24) #cache for a day for rolling results 
def book_read_month_average(book_id, month_start): 
    month_end = month_start + timedelta(days=31) 
    return Reader.objects.filter(book_id=book_id, date_gte=month_start, date_lt=month_end) \ 
         .aggregate(Avg('count'))['count_avg'] 

@cached("author:%s:avg:month:%s", 3600*24) 
def author_read_month_average(author_id, month_start): 
    return sum(book_read_month_average(book.id) 
       for book in Book.objects.filter(author_id=author_id)) 

使用功能成分和缓存功能,您只生成需要的数据,只有当你需要它。您还可以将此信息存储在redis中而不是django缓存中,并利用读取计数的原子增量,实现实时读取统计。

相关问题