読者です 読者をやめる 読者になる 読者になる

redis-objectsで簡単なリアルタイムランキングの実装

rubyのgemにredis-objectsというredisのヘルパーgemがある。

今回、redisを使用して簡易なリアルタイムランキングを実装する機会があったのだけど、とても簡単にできたのでメモしておく。実用的ではないかもしれないが個人のシステムレベルなら使えるかもしれない。

さて、わかりやすくするために今回は記事のリアルタイムアクセスランキングを実装する場合を例にとる。

流れはこう。

  • Redisのsorted setを利用。
  • 記事へのアクセスごと、記事IDをkeyにしてそのscoreをインクリメントする。

これだけ。

実装は以下のような感じ。ホストのセットは公式のREADMEに則った。

Gemfile

gem 'redis-objects'

initializers/redis.rb

Redis::Objects.redis = Redis.new(:host => '127.0.0.1', :port => 6379)

Article.rb

class Article < ActiveRecord::Base
  include Redis::Objects
  sorted_set :ranking

  # 記事IDごとのスコアをインクリメント
  def self.increase_rank_score(article_id)
    article = Article.find(1)  # イケてない
    article.ranking.incr(article_id, 1)
  end

  # 上位1~5位の記事IDを取得
  def self.get_ranking
    article = Article.find(1) # イケてない
    return article.ranking.members.reverse.slice(0,5)
  end

end

articles_controller.rb

class ArticlesController < ApplicationController
    def show
        Article.increase_rank_score(params[:id])
        @article = Article.find(params[:id])
    end
end

rankings_controller.rb

class RankingsController < ApplicationController
    def show
        @ranks = Article.get_ranking
    end
end

Article.rbでは記事へアクセスがあるたびにスコアをインクリメントするメソッドと上位1~5位の記事IDを取得するメソッドを定義。

いちいちオブジェクトを介さないといけないのがイケてない。とりあえずは記事IDを1で代替してる。

articleコントローラでは記事アクセスのたびにincrease_rank_scoreを呼び出す。

rankingコントローラでは上位5位のランキングで記事IDを取得。

こんな感じで実装すると記事ごとのアクセスランキングがリアルタイムで取得できる。

日毎にランキングの結果を残しておきたいという需要があれば作成したsorted setを1日おきに集計してごっそりMySQLとかにいれとけばいい。

他にも似たような仕組みでRedisのCounterを使うと、アクセスカウンタとか作れるかも。

redis便利だ。

おわり。