[WIP] 弱小Railsアプリケーションで日毎のコメント数やユーザー数をなるべく重くない・お手軽な方法で集計したい

TODO

  • 日付毎の投稿数とかコメント数とか集まったいいね数の集計とって、ダッシュボードつくりたい。
  • できればコメント投稿された時にダッシュボードの情報が更新されてて欲しい。
  • グラフを出力するので0件だった時に0件って出て欲しい

制約

  • Rails + Mysql
  • PV月の1万〜2万くらい
  • リリースして1ヶ月ちょっとくらい。
  • 弱小Webアプリケーションだし、変にミドルウェア増やしたりとかでお金かけたくない。なるべくめんどうな方法はとりたくない
  • そこまで解析するデータも全然無いので(一番レコード数多いので1000件とか)有料サービスとかもったいないのでなるべく使わない。

とりあえず、ミドルウェアを追加とかしないで、なるべく他のものを使わず、なんとかできないか試行錯誤してみた。

やったこと

雑にActiveRecord使う

daily_comment_counts = Comment.where(created_at: from..to)
  .group("YEAR(created_at)")
  .group("MONTH(created_at)")
  .group("DAY(created_at)")
  .count()

コメントが存在するときは良いのだけど、データが0件だったときに歯抜けが生じてしまう。(弱小なのでコメントが無い日ももちろんあるのです…) グラフを表示する上で0件だった時に0件って出て欲しいので、却下。

SQL書いた

この辺を参考にして、やってみた。

http://symfoware.blog68.fc2.com/blog-entry-1713.html

あらかじめテーブルを作っといて、それをjoinするみたいな感じ。

これだとデータに歯抜けは生じない。 が、SQLに処理を書きすぎてしまってて、めっちゃ重い。 あと、そこまでSQL力無いので、これをメンテする自信ないし却下。

集計のバッチ書いて、別の集計用のModelに保存しておく

今度試してみる。 ただ、コメントを増えた直後にデータが連動しない。 ダッシュボードのデータがバッチ処理待ちになってしまう。 余裕あれば、AmazonのLambda使ってみたい。

別に集計用のモデル用意して、コメントが追加・削除された時に、集計用のModelの指定の日付のカウント数をインクリメント・デクリメントする

そこまでユーザーいないならって前提で、バイト先の人に聞いたら上記のバッチ処理にするかこの方法にするかのどっちかが良いとかえってきた。 いまはこの方法で進めている。

とりあえず、after_saveとかでモデルの保存や変更にHookして、 指定の日付とアクションに対してのレコードを別の集計用のModelに作っておいて、そこのカウント数をインクリメント・デクリメントしてあげればよいという雑な実装。 あとで理由は書くけど、更新するレコードがない場合は作成するように考慮してあげないといけない。

デメリット

  • とりあえず、できそうだけどなんか納得できてない部分がある。
  • コメント投稿・いいねがされる度に、データベースに対して、Updateがかかるようになってしまっている。
  • もっと他にいい方法があるはず、としか思えない。
  • やっぱり0埋めできないんじゃないの?

0埋めの件

これでやっても、投稿がなければ作成されない。 なので、0埋めをするには前もってレコードを作っておくしか無くて、cronで1日に1回、0時とかに予め更新用のレコードを追加してあげる必要がある。

0時とかの処理中にコメント数とかが増えても困るので、レコードが既に作ってあったら作成しない様にする、

筋が悪い実装かもしれないのでどうにかしたいけど。

稼働中のサービスに対しては?

歯をくいしばってRakeタスク書いて実行するしか無い。

途中から集計するものを増やす場合は?

歯をくいしばってRakeタスク書いて実行するしか無い。

途中からカウントする条件とかを変更する場合は?

歯をくいしばってRakeタスク書いて実行するしか無い。

弱小じゃなくなったらどうするの??

その時は資金力も出るくらいには間違いなくなっているし、リソース割けると思うし、 トレジャーデータなり、ビッククエリなり、スケールしやすそうのを使えばいいのではないでしょうか。 その段階まで来たら、歯をくいしばってRakeタスク書きたくない。

結論

  • ビッククエリとかそこまでしなくてもいいようなサイトさんの泥臭い知見もっと欲しい
  • もちろんこれは不正解な実装な気がするので、もっと詳しい人に話伺いたい。
  • 多分一番良いのはバッチ処理だと思っている。
  • 安くて柔軟に集計とかとれるいいもの・方法を誰か知りませんか?