Hatena::ブログ(Diary)

しばそんノート

2010-02-07

Twitterにおけるニコニコ動画の人気度をランキングするサービスを作ってみた

まだα版ですが、とりあえず見られるレベルにはなったので公開してみます。

Twitterの公開ツイートの中から、ニコニコ動画のURLを含むものを探し出し、ツイート数が多い順に動画をランキングするサービスです。

ニコニコ動画本家のランキングとはだいぶ違う結果になるようなので、見る人が見ればそれなりに楽しいのではないかと…多分。

ツイート数自体がさほど多くありませんが、その分ランキングの入れ替わりは頻繁に起きるようです。

機能面、デザイン面ともにまだまだ作りたてといったところですが、とりあえず仕組みの簡単な説明を書いておこうと思います。

技術的にたいした話はありませんので、日記的な感覚で捉えていただければ幸いです。

開発言語など

Rubyです。データベース操作にSequel、テンプレートエンジンにHaml、memcached操作にmemcache-clientのgemを使用しています。後は細々したものを色々。

ツイートの収集方法

TwitterのStreaming APIを使っています。

結構前にStreaming APIの使い方について記事を書いたのですが、あれから正式版としてリリースされるにあたり、細部がいくらか変更されています。正式版Streaming APIの使い方については、また機会があれば記事にまとめてみたいと思っています。

今回は”statuses/filter”を使い、trackキーワードとして"nico"を指定しています。これはニコニコ動画自体のドメイン="www.nicovideo.jp"と、ニコニコ動画専用のURL短縮サービス”nico.ms”の両方を引っ掛けたかったためです。

[2010年2月10日修正] trackキーワードによる検索は(単語単位での)完全一致で行われますので、上の指定だと"nico.ms"のURLしか引っ掛かりません。"www.nicovideo.jp"も引っ掛けるためには、"nicovideo,nico"というように指定する必要があります。

当然関係ないツイートもかなり紛れ込んでいますので、こんな感じの正規表現でさらにフィルタリングしています。

PATTERN = %r{https?://.*(?:nicovideo\.jp|nico\.ms).*/sm(\d+)}

これにマッチすれば、$1に動画IDが入りますので、それを後々色々と使いまわします。

とってきたツイートは必要な情報だけ取り出して、とりあえずMySQLにぶち込んでいます。ランキング生成などを全部SQLクエリで行えますので、この辺はやはりリレーショナルデータベースが適しています。

ランキングの生成方法

上述の通りSQLクエリで実現しています。Sequelで書くとこんな感じ。テーブル名、カラム名とかの説明は面倒なので省かせてください。

@statuses.filter { |o| o.created_at > Time.now - @target_period }
         .group_and_count(:video_id.as(:video_id))
         .order(:count.desc, :video_id.desc)
         .limit(@max_video_count)

"group_and_count"メソッドが便利ですね。個人的に結構わかりやすく書けるのでお気に入りです、Sequel。

各動画につける最近のツイートは次のような感じで取り出しています。

@statuses.graph(:users, :id => :user_id)
         .filter { |o| o.created_at > Time.now - @target_period }
         .where(:video_id => video_id)
         .order(:created_at.desc)
         .limit(@max_tweet_count)

JOINする双方のテーブルに同名のカラムがある場合、"join"メソッドではなく"graph"メソッドを使うと、結果がテーブル毎のハッシュとして返ってきますので、カラム名の重複を回避することができます。

動画情報の取得

ランキングとして表示するからには、動画の名前やサムネイルなど、色々な情報が必要になってきます。

この辺はニコニコ動画APIとしてきちんと用意されていますので、これを使わせてもらいます。

とりあえず"getthumbinfo" APIを使っておけば、通常必要となる情報は全部取得できます。

今の実装では、トップページの「最新のツイート」を一分ごとに更新していますので、そのままだとかなり頻繁にAPIへアクセスすることになってしまいます。

そこで、取ってきた情報はmemcachedにも保存しておき、memcachedに情報がある場合はAPIへはアクセスしないようにしています。

こういう「とりあえず入れておくだけ」なデータにはリレーショナルデータベースは大げさになってしまいますので、この辺のkey/value式のデータストアが重宝します。

ちなみに、動画情報にはある程度の新鮮さを持たせておきたいので、memcachedに入れたデータも30分経ったら捨てるようにしています。

モジュールの可動場所

サービスのURLはさくらのレンタルサーバですが、ここには静的なHTMLと各種リソースしか置いてありません。上で説明したようなスクリプトは全て自宅で動かしています。

さくらのレンタルサーバではStreaming APIで使うような長寿命のプロセスは許可されていませんし、かといって自宅で固定IPをとってサービスを公開するのもちょっと億劫です。…ということで、こんな構成になりました。

自宅サーバではStreaming APIによるトラッキングの他に、cronで定期的にランキングHTML生成プロセスを動かしており、そいつがさくらサーバ上にアップロードするようになっています。

ちょっと面倒な構成ではありますが、さくらサーバ側の負荷も減りますし、まぁそんなに悪くもないのかな…なんて思っています。

そんなわけで、自宅サーバの能力はフルに使えますので、本当はやろうと思えば1分毎に毎時ランキングを更新する、といったこともできるのですが、それは果たして“毎時ランキング”なのか?という思いもあり、今のような1時間毎の更新としています。

この辺、他の方のご意見も伺いたいところです。

テンプレート

前述の通りテンプレートエンジンはHamlを使っていますが、フォーマットはHTML5で書いています。

といっても新しいAPIとかと使っているわけではなく、タグがHTML5的なだけですが。そのおかげでIEではJavaScriptを無効にしているとレイアウトがガタガタになります。

しかもW3Cのバリデータに通すとエラーになります。どうもHTML5ではmetaタグのhttp-equiv属性に"pragma"や"cache-control"などが使えない*1らしいのですが、さくらサーバでは.htaccessでのキャッシュコントロールはできませんし、仕方なくエラーとなることを承知でそのままにしてあります。

あとはCSS3のborder-radiusとかgradientとかもちょっと使ってみたり。Firefox, Safari, Chromeあたりでしか反映されませんが、その辺のブラウザで見るとちょこっと見た目が変わります。元々のデザインが味気ないので、たいした違いはありませんが。

今後について

Twitterで軽く確認してみましたが、どうやら今の時点では被っているサービスはないようなので*2、もう少し発展させてみようかと思っています。

せっかくStreaming APIを使ってリアルタイムにツイートが取れているのですから、それを活かした機能が欲しいところです。

ニコ動風のUIで、動画のサムネをバックに、取ってきたツイートをリアルタイムで*3流す…みたいなものも考えたのですが、そんなのあまり見ない気がして。どうでしょうね。どちらかというとニコ生風ってことになるのでしょうか。

bit.lyなど、他のURL短縮サービスにも対応できないかと考えましたが、いい案が浮かばないので実現できていません。良い策をご存じの方がいらっしゃいましたらご教示お願い致します。

あとはランキングの更新間隔とか、動画やツイートの表示数とか、細かい部分もあるのですが、なんといってもまずなんとかしたいのはデザインです。

自分デザインセンスは本当に無いもので…。もうちょっと見栄えの良いデザインにしたいなぁ。

そんな感じで、色々迷っているところですので、ご意見ご要望などありましたら是非@shibasonまでご連絡ください。よろしくお願い致します。

あ、あと、名前も募集しています!

*1:まだ定義されていない?

*2:それが一番心配でした。

*3:前述のようにちょっと変わった構成なので、「擬似リアルタイム」的なことしかできないかもしれませんが。