uokadaの見逃し三振は嫌いです

ここで述べられていることは私の個人的な意見に基づくものであり、私が所属する組織には一切の関係はありません。

Redisでセリーグの順位表を作ってみる

Redis使ってますか? 今日はzrankを使わないでセリーグ順位表を作ってみましょう。

例として、下のような順位表があるとします。

Team     Rank 勝 負 分
Tigers   1    5  0 0
Dragons  2    4  1 0
Swallows 3    3  2 0
Giants   4    2  3 0
Carp     5    1  4 0
BayStars 6    0  5 0

順位に関してはなんとなくな個人の趣味で決めてますw *1

上の順位表をデータとしてRedisにセットしましょう。

HMSET Tigers Win 5 Lose 0 draw 0
HMSET Dragons Win 4 Lose 1 draw 0
HMSET Swallows Win 3 Lose 2 draw 0
HMSET Giants Win 2 Lose 3 draw 0
HMSET Carp Win 1 Lose 4 draw 0
HMSET BayStars Win 0 Lose 5 draw 0
SADD central Tigers Dragons Swallows Giants Carp BayStars

上の内容をdata.lstとして保存して下のコマンドを実行します。

% perl -pe 's/\n$/\r\n/g' data.lst |redis-cli --pipe 
All data transferred. Waiting for the last reply...
Last reply received from server.
errors: 0, replies: 7

改行コードをCR+LFにしてパイプラインで流しこんでます。 データの準備はこれで完了です。

あとは、Redisの操作です。 ここからは SORT を駆使していきます。

% redis-cli

# 勝ち数順に並び替え
redis 127.0.0.1:6379> SORT central BY "*->Win"  DESC
1) "Tigers"
2) "Dragons"
3) "Swallows"
4) "Giants"
5) "Carp"
6) "BayStars"

セット型のcentralの要素を見ながら同名のハッシュ型の値を参照してKey名Winの値を基準に並べ替えています。

これで大体のことは出来ました。あとはオマケです。

# 勝ち数順に並び替え + チーム名と勝ち数を取得
redis 127.0.0.1:6379> SORT central BY "*->Win"  GET # GET "*->Win" DESC
 1) "Tigers"
 2) "5"
 3) "Dragons"
 4) "4"
 5) "Swallows"
 6) "3"
 7) "Giants"
 8) "2"
 9) "Carp"
10) "1"
11) "BayStars"
12) "0"
# 勝ち数順に並び替え + 勝ち数と負け数を取得
redis 127.0.0.1:6379> SORT central BY "*->Win" GET "*->Win" GET "*->Lose" DESC
 1) "5"
 2) "0"
 3) "4"
 4) "1"
 5) "3"
 6) "2"
 7) "2"
 8) "3"
 9) "1"
10) "4"
11) "0"
12) "5"

上位3チームだけ必要な場合はLIMIT句を使うことで実現出来ます。

# 勝ち数順に並び替え + チーム名と勝ち数を上位3チームまで取得
redis 127.0.0.1:6379> SORT central BY "*->Win" LIMIT 0 3 GET # GET "*->Win" GET "*->Lose" DESC
1) "Tigers"
2) "5"
3) "0"
4) "Dragons"
5) "4"
6) "1"
7) "Swallows"
8) "3"
9) "2"

SORTコマンドってこうやってみていくとSQLっぽいですね。 あと、順位表っぽく加工するのはpythonとかの言語を使ってやれば簡単に出来るかなと思います。 シェルで順位表作るのは自分の実力では無理でしたorz

ちなみに、pythonで操作するとこんな感じです。

import redis
r = redis.Redis()
results = r.sort("central", by="*->WIn", get=["#", "*->Win", "*->Lose"], desc=True)

for i, team in enumerate(teams):
  print "%s %s %s" % (team, results[i * 3 +1], results[i * 3 + 2])                                                                                           

# Tigers 5 0
# Swallows 3 2
# Giants 2 3
# Dragons 4 1
# Carp 1 4
# BayStars 0 5

このランキングの作り方だとzrankで作るよりも柔軟にランキングが作れることが魅力です。 欠点は6チーム中何位みたいなランキングを作ることは難しいです。 できなくも無いですがすべての要素をソートしてどこにあるか確定させる必要があるので要素数が多くなるとパフォーマンスの問題が発生が起こります。

要素数があまり大きくなく(多分、n<10000)、上位100位ぐらいまで表示させたいならこの方法でも十分なパフォーマンスが出せるでしょう。

こんな感じでSORT + HASH型 + SET型を組み合わせれば ソート済みSET型を使わなくても簡単なランキングが作れるという話でした〜。 

WEB+DB PRESS Vol.73

WEB+DB PRESS Vol.73

  • 作者: 設樂洋爾,白土慧,奥野幹也,佐藤鉄平,後藤秀宣,mala,中島聡,堤智代,森田創,A-Listers,はまちや2,大和田純,松田明,後藤大輔,ひろせまさあき,小林篤,近藤宇智朗,まかまか般若波羅蜜,Mr. O,WEB+DB PRESS編集部
  • 出版社/メーカー: 技術評論社
  • 発売日: 2013/02/23
  • メディア: 大型本
  • 購入: 12人 クリック: 131回
  • この商品を含むブログ (4件) を見る

*1:5位力のカープと最下位ベイスターズ以外は適当に決めました。