Railsアプリケーションで検索結果を記録します
-
22-09-2019 - |
質問
アイテムが検索またはリストページで表示される回数のログと計算に興味があります。 1日に50kのユニークな訪問者がいるため、1日あたり3〜400万人の「インプレッション」を生み出すことができると予想していますが、これはひどく大量ではありませんが、私たちはうまく建築したいと思います。
このデータをリアルタイムで読む必要はありませんが、ビジネス分析ツールと同様に、毎日の合計を生成し、トレンドなどを分析できるようにしたいと考えています。
ページがレンダリングされた後、AJAXの投稿でこれを行うことを計画しています。これにより、これらの結果がキャッシュされていても結果をカウントできます。これを1ページごとに1つの投稿で行うことができ、ページ上のIDとその位置のコンマ区切りリストを送信できます。
これについてのデザインパターン/GEM/ブログの投稿があることを願っています。また、ログのログや読み物の読み物の経験はあまりありません。
私の現在の戦略 - ログファイルにイベントを書く何かを作成し、1日の終わりに結果を集計し、結果をMySQLに戻すためのバックグラウンドジョブを作成します。
解決
アイテムをリストするのに必要なアクションがないことに応じて、コントローラーでそれを行い、往復することができるかもしれません。 afth_filterでそれを行うことができ、追加を控えめにすることができます。
これは、ログを記載するアイテムをリストするすべてのアクションにパラメーターが必要な場合にのみ機能します。これは、Page Cachingがパラメーターを使用してGETリクエストを無視するためです。
検索アクションに関する検索データのみを記録するだけであると仮定します。
class ItemsController < ApplicationController
after_filter :log_searches, :only => :search
def log_searches
@items.each do |item|
# write to log here
end
end
...
# rest of controller remains unchanged
...
end
それ以外の場合は、Ajaxとオンロードリモート機能で順調に進んでいます。
処理に関しては、Cronジョブが実行するレーキタスクを使用して統計を収集し、場合によっては人気評価のためにアイテムを更新できます。
いずれにせよ、あなたは ルビーロギングクラス. 。 Cronの仕事やレーキのタスクについて学ぶことも傷つくことはありません。
他のヒント
わかりました、私はあなたのために3つのアプローチがあります:
1)キュー
Ajaxハンドラーで、可能な限り単純な方法(ラックミドルウェアまたはRails Metalを使用)を書き、クエリパラメーションをキューに押し込みます。次に、キューを投票してメッセージを収集します。
ラックからプッシュされるキューミドルウェアは目がくらむほど速いです。これは、同様のデータを記録するために非常に高い交通サイトで使用します。
ラックのサンプルミドルウェアは以下にあります(アプリから抽出され、2ms未満でリクエストを処理できます。
class TrackingMiddleware
CACHE_BUSTER = {"Cache-Control" => "no-cache, no-store, max-age=0, must-revalidate", "Pragma" => "no-cache", "Expires" => "Fri, 29 Aug 1997 02:14:00 EST"}
IMAGE_RESPONSE_HEADERS = CACHE_BUSTER.merge("Content-Type" => "image/gif").freeze
IMAGE_RESPONSE_BODY = [File.open(Rails.root + "public/images/tracker.gif").read].freeze
def initialize(app)
@app = app
end
def call(env)
if env["PATH_INFO"] =~ %r{^/track.gif}
request = Rack::Request.new(env)
YOUR_QUEUE.push([Time.now, request.GET.symbolize_keys])
[200, IMAGE_RESPONSE_BODY, IMAGE_RESPONSE_HEADERS]
else
@app.call(env)
end
end
end
キューにはお勧めします スターリング, 、私はそれで楽しい時間を過ごしました。
解析の終わりに、私は使用します スーパーポラーツールキット, 、しかし、私はそれを書いたと思います。
2)ログ
Query Paramsを静的ファイル(/1x1.gif?foo=1&bar=2&baz=3)にすべてのパラメーションを渡します。これはRailsスタックに衝突することはなく、目がくらむほど速くなります。
データが必要な場合は、ログファイルを解析するだけです!
これは、最高のスケーリングホームブリューアプローチです。
3)Googleアナリティクス
Googleがあなたのためにそれを行うのに、なぜ負荷を処理するのですか? Google Analyticsがどれほど優れているかに驚くでしょう。家に帰る前に、チェックしてください!
Googleはあなたよりも速くサーバーを購入するため、これは無限にスケーリングされます。
私はこれについて何年もの間怒ることができましたが、私は今行かなければなりません。お役に立てれば!
これは私が最終的にしたことです - 今のところ私たちの使用には十分であり、いくつかの簡単なベンチマークで、私はそれについて大丈夫だと感じています。顧客に結果を公開する前に、生産がどのように行われているかを確認します。
コンポーネント:
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 %>
次に、これらの列のコンマ区切りIDをDBにインポートするためのレーキタスクを作成しました。これは翌日に実行されます:
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
注意すべきことの1つは、ロガー変数がコントローラーアクションで宣言されています - 環境ではなく、通常はロガーで行うように。私はこれをベンチマークしました-10000の執筆には約20秒かかりました。平均で約2ミリ秒の書き込み。 Envirnment.RBにファイル名があると、約14秒かかりました。このトレードオフを行い、ファイル名を動的に決定できるようにしました。これは、真夜中にファイルを切り替える簡単な方法です。
この時点での私たちの主な関心事 - 1日あたりの異なるアイテムの数が何度もカウントされるのかわかりません - すなわち。尾の長さはわかりません。これにより、毎日DBに追加される行の数が決まります。毎日のレポートを維持し、その時点でさらに結果をさらに役立たせるかを制限する必要があると期待しています。