2014-01-11 36 views
0

我有三個型號,用戶,地點,評級,具體如下:如何高效率,獲取平均評分模型的Rails中

class User < ActiveRecord::Base 
    has_many :ratings 
end 

class Venue < ActiveRecord::Base 
    has_many :ratings 
end 

class Rating < ActiveRecord::Base 
    belongs_to :user 
    belongs_to :venue 
end 

用戶能夠從0-5打分場地。用戶可以按照他們想要的頻率對場地進行評級,並且他們通常在相同的場地內相同的用戶在不同的分鐘內創建不同的評級。

我希望能夠提供的平均評級從過去一小時場地的,但我只希望從時間考慮每個用戶一個等級。因此,如果用戶在過去一小時內多次對同一場地進行評級,則只會計入他們最近的評級。

目前我有這樣的:

class Venue < ActiveRecord::Base 
    has_many :ratings 

    def past_hour_average 
    ratings = self.ratings.where(:created_at => 1.hour.ago..Time.now).uniq_by(&:user_id) 
    # loop through each record and compute average 
    sum = 0 
    ratings.each do |rating| 
     sum += rating.value 
    end 
    return sum/ratings.size 
    end 
end 

這種方法似乎效率不高但是。每次我想要一個場地的評分時,我都要計算它。 假設有很多用戶經常對單個場地進行評級,那麼計算平均評級的更好方法是什麼?

回答

1

我認爲這應該工作:

def past_hour_average 
    ratings = self.ratings.where(created_at: 1.hour.ago..Time.now).order(:created_at).group(:user_id) 

    ratings.sum(:value)/ratings.count 
end 

你可能只是需要反向排序如果返回的最古老的,而不是最近的評級從每個用戶。

這是做你的代碼不正是......它只是獲取數據庫做的和你而不是你的Ruby代碼中手工計算的方法。

1

你確定,這個計算的效率,甚至會成爲一個問題?我認爲這是不太可能的,除非你的網站經歷非常,非常重讀取負載。

但這真的很重要,這裏是你可以做這可能有助於一點點一件簡單的事情:

def past_hour_average 
    @past_hour_average ||= begin 
    # calculation here 
    end 
end 

這將確保在單一地點的計算不超過一次單個請求的空間。

如果你需要比這更好,而且你確實已經檢查確定這是確實是的問題,那麼你可以緩存計算結果並在緩存超過特定分鐘數時使其無效。我不打擾MemCached(等)在這裏。我只想做這樣的事情:

class Venue 
    @@avg_rating_cache = {} 

    def past_hour_average 
    if avg,time = @@avg_rating_cache[self.id] && time > (Time.now - 10.minutes) 
     @@avg_rating_cache[self.id] = [avg, Time.now] 
     return avg 
    end 

    value = calculation_here 
    @@avg_rating_cache[self.id] = [value, Time.now] 
    value 
    end 
end 

這將直接在每個應用程序的內存緩存結果(所以會出現訪問一個memcached的緩存中沒有額外的開銷/延遲)。如果您的場地超過10,000個,則需要從緩存中刪除條目,因爲新添加的條目可防止過多的內存使用。

+0

我不熟悉的軌道cacheing但會考慮。你也許沒有必要擔心負載。謝謝! – steve