「にほんのあらそい」のランキングサイトを実装したので、技術情報や雑感などをメモ
ぐんまのやぼうをはじめとして、RucKyGAMESさんのアプリにはいろいろとお世話になっているなぁ…と日頃からつくづく感じていた今日この頃ではあったのですが...。
と、思い付いたままのことをうっかりつぶやいてしまったがために、各所からの見えないプレッシャーのもとランキングサイトを実装することになってしまいました。
んで、構想5分、実装数時間くらいで、こんなものが完成しました。
いろいろと忙しいあたりだったのですけど、結果として以下の通り最低限のものが出来てるので良かったとは思っています。
こういうものを作りっぱなし…というのもいまいちなので、ここでは主に技術的な話を中心に紹介させて頂きたいと思います。はい。
システム構成
本サイトのシステム構成は、以下のような感じになってます。
今回Sinatraを採用したのには、「思いついたアイデアを即実装」というスピード感では、Sinatraのような軽量フレームワークが最適解だと判断した、という理由と、さくらVPS1Gのような比較的poorな実行環境では、Railsのような重量級フレームワークを動作させるのは少し心もとなかった、という理由があります。
またMongoDBについては、クローズドな環境で試したことは何度かあったのですが、オープンなサイトで使用したのは今回が実は初めてでした。採用した理由は特になんとなくで「スキーマレスだし気楽に使えるからいいかなー?」程度のものでした。
RubyプロセスでTwitterの情報を取得
「にほんのあらそい らんきんぐ」のWebアプリとは別に、Twitterのつぶやきから都道府県別の制圧状況を取得するRubyプロセスを動かしています。具体的には以下のような動きになっています。
- Twitter Search APIを使って、「iPhone版アプリのURL」「Android版アプリのURL」を含むツイートを取得
- 取得したツイートから、にほんのあらそいのハッシュタグ(#japanapps01〜japanapps47)を含むツイートのみを抽出
- 抽出したツイートの都道府県番号のみをMongoDBにinsert
最初は「『#japanapps』で検索すれば一発で引っ掛かるんじゃね??」と思ってみたのですが、Twitter Search APIの仕様上ハッシュタグの前方一致検索は出来ないようでして、01〜47まで47回APIを呼びだすわけにもいかないので、現在のようにアプリURLで引っ掛けて取ってくるような実装になっています。
いちおうSearch APIにも(IPアドレス単位の)rate limit的なものは存在するようなのですが、#japanapps01〜47全て合わせても追いつける程度の流速であるため、特に工夫もせず、rate limitに達しない程度の間隔で定期的にAPIをcallするような動きにしています。
ランキングの表示
で、Webアプリ側の説明なのですが、上のプログラムでMongoに溜めこんだデータを「count(*) 〜 group by 〜」に相当する処理でランキング化して表示している、だけになります。
ちなみにUI周りについては、以下のものを使っています。
- Twitter Bootstrap
- jqPlot
見た目をTwitter Bootstrapでお気楽に仕上げてしまってることについては本当にごめんなさい。お気楽な感じでそれっぽいUIが出来上がってしまうのは本当に便利ですよねー。
棒グラフの表示にはjpPlotを使用しているのですけど、スマートフォンのリキッドレイアウトとは非常に相性が悪く、(一応見れてはいると思うのですが)スマートフォン対応が非常に甘くなってしまっております。
で、所感など
やっぱりSinatraは最高!
普段仕事をしている時には「それなりに工数を掛けてじっくり作りこみたいときはRuby+Rails」「時間が無くてエイヤで作り捨てるときはPHP」というような住み分けが出来てしまっているのですが、Rubyの実行環境がしっかり整っている場合にはSinatraでさくっと作ってしまうのがとてもスマートだなぁと感じました。
PHPでエイヤで作ってしまうのと同程度のスピードで実装出来てしまう上に、RSpecの恩恵にも与ることが出来てしまうのが素晴らしい。
少なくとも「初見の想像の範囲で設計が完了してしまう」規模のアプリケーションについては、数時間のオーダーで実装を済ませてしまう為のアプリケーションフレームワークとして、Sinatraはまさに最適解なのでは、と思っています。
MongoDBも便利!でも集計処理が遅い…。
上記と同様に、「スキーマのことを考えずにJSONをそのまんまinsertするだけで実装出来てしまう」という意味においては、MongoDBも非常に有用なデータベースシステムなのではないかと考えています。そうなのですが…。
本サイトの場合「ランキングを表示しなければならない」という特性上、「集計処理」というものは不可欠なものになってくるのですが、そちらの実行速度がいまいちだったりするのです…。
6/11現在、コレクション内のドキュメント数は約10万程度なのですが、これらを47都道府県別に集計してそれぞれの件数をカウントする処理、SQLで言うところの「count(*) 〜 group by 〜」に相当する処理だけでも、実行に3〜4秒程度を要してしまうのは若干残念な感じです。インデックスを張ってみたりだとか、MapReduceを利用してみたりだとか、色々試行錯誤はしてみたのですが満足な結果は得られず…。
もうしばらくすると、データ数的にもいい加減容認出来ないくらいになってくるので、それまでには何らかの対策を考えたいと思っています…。このままだとMySQLに移行する形になるのでしょうけど…。