2012-02-15 278 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緩存中,並利用讀取計數的原子增量,實現實時讀取統計。

相關問題