Ruby+Redisでランキングを実装してみる
Redisでランキング機能を実装してみる - (゚∀゚)o彡 sasata299's blog を自分がやったらこんな感じかなと思って書いてみました。実行環境はRuby 2.0.0-p0です。
#!/usr/bin/env ruby require 'redis' require 'pp' class Leaderboard class Entry attr_reader :user_id, :score, :rank def initialize(user_id, score, rank) @user_id = user_id @score = score @rank = rank end def inspect "#<#{self.class} user_id:#{user_id}, score:#{score}, rank:#{rank}>" end end def initialize(id, user_id) @r = Redis.new @id = id @user_id = user_id end def _add(user_id, score) @r.zadd @id, score, user_id end def add(score) @r.zadd @id, score, @user_id end def get_score @r.zscore @id, @user_id end def get_rank @r.zrank @id, @user_id end def get_range(start, count) p [start, count] @r.zrange(@id, start, start + count, with_scores: true).map.with_index do |pair, i| Entry.new *pair, start + i + 1 end end def get_current_page_num(num_per_page) (get_rank / num_per_page).floor end def get_page(page_num, num_per_page) get_range page_num * num_per_page, num_per_page end def get_current_page(num_per_page) get_page get_current_page_num(num_per_page), num_per_page end end # example code l = Leaderboard.new "ranking", "bar" 8.times do |i| l._add "foo#{i}", 100 + i end 8.times do |i| l._add "baz#{i}", 300 + i end l.add 200 p l.get_score p l.get_rank p l.get_current_page_num 5 puts "current_page:" # 自分がいるページ(1ページに付き5エントリ) pp l.get_current_page 5 # ふつうにページングする場合 puts "page 0, 1, 2:" pp l.get_page 0, 5 pp l.get_page 1, 5 pp l.get_page 2, 5
実行結果(+コメント):
200.0 # 自分のスコア 8 # 自分の順位 1 # 自分が今いるページ (0 origin) current_page: [#<Leaderboard::Entry user_id:foo5, score:105.0, rank:6>, #<Leaderboard::Entry user_id:foo6, score:106.0, rank:7>, #<Leaderboard::Entry user_id:foo7, score:107.0, rank:8>, #<Leaderboard::Entry user_id:bar, score:200.0, rank:9>, # 自分はここ #<Leaderboard::Entry user_id:baz0, score:300.0, rank:10>, #<Leaderboard::Entry user_id:baz1, score:301.0, rank:11>] page 0, 1, 2: # ふつうにページング page 0: [#<Leaderboard::Entry user_id:foo0, score:100.0, rank:1>, #<Leaderboard::Entry user_id:foo1, score:101.0, rank:2>, #<Leaderboard::Entry user_id:foo2, score:102.0, rank:3>, #<Leaderboard::Entry user_id:foo3, score:103.0, rank:4>, #<Leaderboard::Entry user_id:foo4, score:104.0, rank:5>, #<Leaderboard::Entry user_id:foo5, score:105.0, rank:6>] page 1 (current page): [#<Leaderboard::Entry user_id:foo5, score:105.0, rank:6>, #<Leaderboard::Entry user_id:foo6, score:106.0, rank:7>, #<Leaderboard::Entry user_id:foo7, score:107.0, rank:8>, #<Leaderboard::Entry user_id:bar, score:200.0, rank:9>, #<Leaderboard::Entry user_id:baz0, score:300.0, rank:10>, #<Leaderboard::Entry user_id:baz1, score:301.0, rank:11>] page 2: [#<Leaderboard::Entry user_id:baz1, score:301.0, rank:11>, #<Leaderboard::Entry user_id:baz2, score:302.0, rank:12>, #<Leaderboard::Entry user_id:baz3, score:303.0, rank:13>, #<Leaderboard::Entry user_id:baz4, score:304.0, rank:14>, #<Leaderboard::Entry user_id:baz5, score:305.0, rank:15>, #<Leaderboard::Entry user_id:baz6, score:306.0, rank:16>]
参考文献
redis.rbのドキュメント: http://rubydoc.info/gems/redis/frames
Redis/Sorted Setのドキュメント:http://redis.io/commands#sorted_set
Redis大活用 - リアルタイムランキングの実装 in WEB+DB PRESS vol.73
- 作者: 設樂洋爾,白土慧,はまちや2,大和田純,松田明,後藤大輔,ひろせまさあき,小林篤,近藤宇智朗,まかまか般若波羅蜜,Mr. O,川添貴生,重国和宏,柳澤建太郎,奥野幹也,佐藤鉄平,後藤秀宣,mala,中島聡,堤智代,森田創,A-Listers,WEB+DB PRESS編集部
- 出版社/メーカー: 技術評論社
- 発売日: 2013/02/23
- メディア: 大型本
- 購入: 12人 クリック: 131回
- この商品を含むブログ (7件) を見る