カテゴリー:
Rails
タグ:
 Rails Redis

このエントリーをはてなブックマークに追加
更新日時:
2017年09月26日(火)
作成日時:
2017年09月26日(火)

前の記事 / 次の記事

細かい設定は割愛してとりあえず動かすところまで。

環境

CentOS: 6.8
Rails: 5.1.4
Ruby: 2.3.1p112
Redis 3.2.10

参考

インストール

yumで入れるとたぶん最新版入らないので
最新版を入れる場合は最新版をインストールできるリポジトリを登録するか
ソースからインストール。

今回はとりあえず動かしたいのでバージョンは気にせずとりあえず入れる。

インストール
$ sudo yum install redis

起動
$ sudo /etc/init.d/redis start

サーバー起動時に自動的に起動するように設定
$ sudo chkconfig redis on

Railsの環境を設定

何はともあれgemをインストール。

$vi Gemfile
gem 'redis'

$ bundle install

とりあえず "config/initializers/redis.rb" に書いておく。
Redisは6379番ポートをデフォルトで使用するようになっているので、
6379番ポートを指定する、他のポートを使う場合はRedisの設定で変更する。

$ vi config/initializers/redis.rb
REDIS = Redis.new(host: "localhost", port: 6379)

Rails上でRedisを動かすコードを書いてみる

ググってみたところ丁度良さそうなサンプルがあったので写経してみる。

とりあえずアクセスランキング的な何かをつくってみる

写経元:http://seishin55.hatenablog.com/entry/2016/05/02/214513

ブログの記事に対するPV数の計測と、PV数からランキングを作成する。

アクセス数を記録するコード

参考:Method: Redis#zincrby

class Article < ApplicationRecord
  def redis_access
    REDIS.zincrby "articles", 1, @article.id
  end
end

class ArticlesController < ApplicationController
  def show
    @article.redis_access
  end
end

Redisのデータ構造は、ハッシュに例えて考えた場合、次のようになっているのだが、

key: { 
  member1: score1,
  member2: score2,
  member3: score3
}

REDIS.zincrby というメソッドで articles(key) の @article.id(member) である値を
1インクリメントして保存することができる。

今回の場合はこのコードで、次のようなデータを保存することができる。

#
# articles: {
#   記事id: PV数
# }
#
articles: {
  1: 1,
  2: 5,
  3: 3
}

アクセスランキングを作成するコード

参考:Method: Redis#zrevrangebyscore

class Article < ApplicationRecord
  def most_popular(limit: 5)
    most_polular_ids = REDIS.zrevrangebyscore "articles", "+inf", 0, limit: [0, limit]
    where(id: most_polular_ids).sort_by{ |article| most_popular_ids.index(article.id.to_s) }
  end
end

# 適当なViewで
%h1 アクセスランキング
%ol
  - Article.most_polular.each do |article|
    %li= "#{article.id}: #{article.title}"

REDIS.zrevrangebyscore というメソッドで値の大きい順にソートされたデータを取得することができる(降順)。
値の小さい順に取得する場合は、REDIS.zrangebyscore を使う。revっていうのはreverseのrevですね。

今回の場合、このメソッドで、articles をキーとしてアクセスされるデータの内、
その値が無限(+inf)~0であるメンバーを値の大きい順位5件取得することができる。

この時、メンバー名はarticle.idなので次のようなデータが取得される。

most_popular_ids = REDIS.zrevrangebyscore "articles", "+inf", 0, limit: [0, 5]
# most_polular_ids => [3, 5, 2, 4, 1]

そして、where(id: most_polular_ids)で取得される値の順序は保証されていないので、

where(id: most_polular_ids).sort_by{ |article| most_popular_ids.index(article.id.to_s) }

でソートし直す(配列の位置の小さい順に整列)。

値(スコア)を取得するコード

ランキングが欲しい場合は整列されたデータが欲しいが、
PV自体が欲しい場合は個々の値が欲しい。

それは次のコードで取得することができる。

class Article < ApplicationRecord
  # 浮動小数点数で格納されているので小数点以下を切り捨てる
  def redis_page_view
    REDIS.zscore("articles", @article.id).floor
  end
end

# 適当なViewで
%h1= @article.title
%dl
  %dt PV
  %dd= @article.redis_page_view

とりあえずここまで。