这就是我最终所做的——这对于我们现在的使用来说已经足够了,并且通过一些简单的基准测试,我觉得还可以。在我们将结果展示给客户之前,我们将观察它在生产中的表现。
组件:
class EventsController < ApplicationController
def create
logger = Logger.new("#{RAILS_ROOT}/log/impressions/#{Date.today}.log")
logger.info "#{DateTime.now.strftime} #{params[:ids]}" unless params[:ids].blank?
render :nothing => true
end
end
这是从站点布局中的 ajax 调用调用的...
<% javascript_tag do %>
var list = '';
$$('div.item').each(function(item) { list += item.id + ','; });
<%= remote_function(:url => { :controller => :events, :action => :create}, :with => "'ids=' + list" ) %>
<% end %>
然后我做了一个 rake 任务,将这些逗号分隔的 id 行导入到数据库中。第二天运行:
desc "Calculate impressions"
task :count_impressions => :environment do
date = ENV['DATE'] || (Date.today - 1).to_s # defaults to yesterday (yyyy-mm-dd)
file = File.new("log/impressions/#{date}.log", "r")
item_impressions = {}
while (line = file.gets)
ids_string = line.split(' ')[1]
next unless ids_string
ids = ids_string.split(',')
ids.each {|i| item_impressions[i] ||= 0; item_impressions[i] += 1 }
end
item_impressions.keys.each do |id|
ActiveRecord::Base.connection.execute "insert into item_stats(item_id, impression_count, collected_on) values('#{id}',#{item_impressions[id]},'#{date}')", 'Insert Item Stats'
end
file.close
end
需要注意的一件事 - 记录器变量是在控制器操作中声明的 - 而不是在 environment.rb 中,就像您通常对记录器所做的那样。我对此进行了基准测试 - 10000 次写入大约需要 20 秒。平均一次写入大约需要 2 毫秒。使用 envirnment.rb 中的文件名,大约需要 14 秒。我们进行了这种权衡,以便我们可以动态确定文件名 - 一种在午夜切换文件的简单方法。
在这一点上,我们主要关心的是——我们不知道每天将计算多少不同的项目——即。我们不知道尾巴有多长。这将确定每天向数据库添加多少行。我们预计我们将需要限制我们保留每日报告的时间,并且届时将进一步提升结果。