Ruby on rails 如何在Rails中有效地对模型进行评级和检索平均评级
我有三种型号,用户、场地、评级,如下所示:Ruby on rails 如何在Rails中有效地对模型进行评级和检索平均评级,ruby-on-rails,Ruby On 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 class用户
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
class用户
用户可以从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.hour.ago..Time.now).uniq_by(&:user_id)
#循环遍历每个记录并计算平均值
总和=0
评级。每个do |评级|
总和+=额定值
结束
返回值/额定值。大小
结束
结束
然而,这种方法似乎效率低下。每次我想要一个场馆的评级,我都要计算它。
假设有许多用户经常对单个场馆进行评分,那么计算平均评分的更好方法是什么?我认为这应该是可行的:
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代码中手动计算。我认为这应该可以:
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代码中手动计算。您确定这种计算的效率会成为一个问题吗?我认为这是不太可能的,除非你的站点体验“强>非常,非常/强”重读负载。 但这确实很重要,这里有一件简单的事情你可以做,这可能会有点帮助:
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缓存不会产生额外的开销/延迟)。如果您有超过10000个场地,则需要在添加新的场地时将其从缓存中逐出,以防止过度使用内存。您确定此计算的效率会成为一个问题吗?我认为这是不太可能的,除非你的站点体验“强>非常,非常/强”重读负载。 但这确实很重要,这里有一件简单的事情你可以做,这可能会有点帮助:
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缓存不会产生额外的开销/延迟)。如果您有超过10000个场地,则需要在添加新的场地时从缓存中逐出条目,以防止内存过度使用。我不熟悉rails中的缓存,但会研究一下。您不必担心负载,这可能是对的。谢谢我不熟悉rails中的缓存,但会深入研究。您不必担心负载,这可能是对的。谢谢