Redis Sorted Sets(パート1)
Sorted Setはスコアを持つセットで、要素はスコアでソートされます。このレッスンでは、基本的なソート済みセット操作について解説します。
Sorted Setとは
Sorted Setの特徴:
- 順序付け:要素はスコアでソートされます(昇順)
- 一意:要素は一意ですが、スコアは重複可能です
- 各要素がスコアを持つ:ソートに使用されます
leaderboard
├─ "player1" → score: 100
├─ "player2" → score: 200
├─ "player3" → score: 300
└─ "player4" → score: 400
💡 内部実装: Sorted Setはスキップリスト+ハッシュテーブルを使用しています。スキップリストは効率的なソートと範囲クエリをサポートし、ハッシュテーブルは高速なスコア検索を可能にします。
ZADD:要素の追加
基本的な使用方法
REDIS
# 単一の要素を追加
ZADD leaderboard 100 "player1"
(integer) 1 # 新しく追加された要素の数を返す
# 複数の要素を追加
ZADD leaderboard 200 "player2" 300 "player3" 400 "player4"
(integer) 3
ZADDのパラメータ
REDIS
# NX:新しい要素のみ追加、既存のものは更新しない
ZADD leaderboard NX 150 "player1"
(integer) 0 # player1は既に存在、更新されない
# XX:既存の要素のみ更新、新しいものは追加しない
ZADD leaderboard XX 500 "player5"
(integer) 0 # player5は存在しない、追加されない
# CH:変更された要素の数を返す(更新を含む)
ZADD leaderboard CH 120 "player1"
(integer) 1 # player1のスコアを更新
# INCR:スコアを増加(ZINCRBYと同等)
ZADD leaderboard INCR 50 "player1"
"170" # 新しいスコアを返す
既存要素のスコア更新
REDIS
# 要素が既に存在する場合、スコアが更新される
ZADD leaderboard 250 "player1"
# 新しいスコアを表示
ZSCORE leaderboard "player1"
"250"
ZSCORE:要素のスコアを取得
REDIS
ZADD leaderboard 100 "player1" 200 "player2"
# スコアを取得
ZSCORE leaderboard "player1"
"100"
# 要素が存在しない場合
ZSCORE leaderboard "notexist"
(nil)
ZRANKとZREVRANK:ランクを取得
ZRANK:低い方からのランク
REDIS
ZADD leaderboard 100 "player1" 200 "player2" 300 "player3"
# ランクは0から始まる
ZRANK leaderboard "player1"
(integer) 0 # 1位(最も低いスコア)
ZRANK leaderboard "player2"
(integer) 1 # 2位
ZRANK leaderboard "player3"
(integer) 2 # 3位
ZREVRANK:高い方からのランク
REDIS
# 高い方からのランク(最も高いスコアがランク0)
ZREVRANK leaderboard "player3"
(integer) 0 # 1位(最も高いスコア)
ZREVRANK leaderboard "player2"
(integer) 1 # 2位
ZREVRANK leaderboard "player1"
(integer) 2 # 3位
💡 ランクルール:
- ZRANK:低いスコアから高いスコアへ、最も低いスコアがランク0
- ZREVRANK:高いスコアから低いスコアへ、最も高いスコアがランク0
- ランクは0から始まり、1位のランクは0
ZRANGEとZREVRANGE:ランク範囲で要素を取得
ZRANGE:ランク範囲で取得(低い方から)
REDIS
ZADD leaderboard 100 "player1" 200 "player2" 300 "player3" 400 "player4"
# すべての要素を取得
ZRANGE leaderboard 0 -1
1) "player1"
2) "player2"
3) "player3"
4) "player4"
# 最初の2要素を取得
ZRANGE leaderboard 0 1
1) "player1"
2) "player2"
# 最後の2要素を取得
ZRANGE leaderboard -2 -1
1) "player3"
2) "player4"
# スコア付きで要素を取得
ZRANGE leaderboard 0 -1 WITHSCORES
1) "player1"
2) "100"
3) "player2"
4) "200"
5) "player3"
6) "300"
7) "player4"
8) "400"
ZREVRANGE:ランク範囲で取得(高い方から)
REDIS
# 高い方からすべての要素を取得
ZREVRANGE leaderboard 0 -1 WITHSCORES
1) "player4"
2) "400"
3) "player3"
4) "300"
5) "player2"
6) "200"
7) "player1"
8) "100"
# トップ3を取得(最も高いスコア)
ZREVRANGE leaderboard 0 2 WITHSCORES
1) "player4"
2) "400"
3) "player3"
4) "300"
5) "player2"
6) "200"
ZCARD:要素数を取得
REDIS
ZADD leaderboard 100 "player1" 200 "player2" 300 "player3"
ZCARD leaderboard
(integer) 3
ZCOUNT:スコア範囲内の要素をカウント
REDIS
ZADD leaderboard 100 "player1" 150 "player2" 200 "player3" 250 "player4" 300 "player5"
# スコアが150〜250の要素をカウント
ZCOUNT leaderboard 150 250
(integer) 3 # player2、player3、player4
# -inf と +inf を使用
ZCOUNT leaderboard -inf +inf
(integer) 5 # すべての要素
ZREM:要素の削除
REDIS
ZADD leaderboard 100 "player1" 200 "player2" 300 "player3"
# 単一の要素を削除
ZREM leaderboard "player1"
(integer) 1
# 複数の要素を削除
ZREM leaderboard "player2" "player3"
(integer) 2
# 存在しない要素を削除
ZREM leaderboard "notexist"
(integer) 0
ZINCRBY:スコアの増加
REDIS
ZADD leaderboard 100 "player1"
# スコアを50増加
ZINCRBY leaderboard 50 "player1"
"150" # 新しいスコアを返す
# スコアを減少(負の数を渡す)
ZINCRBY leaderboard -20 "player1"
"130"
Sorted Setのユースケース
ユースケース1:ゲームリーダーボード
REDIS
# プレイヤーのスコアを更新
ZADD game:leaderboard 1500 "player:123"
ZADD game:leaderboard 2300 "player:456"
ZADD game:leaderboard 1800 "player:789"
# トップ10を取得
ZREVRANGE game:leaderboard 0 9 WITHSCORES
# プレイヤーのランクを取得
ZREVRANK game:leaderboard "player:123"
# プレイヤーのスコアを増加
ZINCRBY game:leaderboard 100 "player:123"
ユースケース2:トレンド検索
REDIS
# トレンドの熱度スコアを更新
ZADD hot:search 10000 "Redis tutorial"
ZADD hot:search 8000 "Python basics"
ZADD hot:search 15000 "JavaScript"
# トップ10のトレンドを取得
ZREVRANGE hot:search 0 9 WITHSCORES
# 熱度スコアを増加
ZINCRBY hot:search 100 "Redis tutorial"
ユースケース3:遅延キュー
REDIS
# 遅延タスクを追加(スコアは実行タイムスタンプ)
ZADD delay:queue 1719129600 "task:1" # 2024-06-23 10:00:00
ZADD delay:queue 1719133200 "task:2" # 2024-06-23 11:00:00
# 現在時刻より前のタスクを取得(実行すべきタスク)
ZRANGEBYSCORE delay:queue -inf 1719129600
ユースケース4:重み付きタグ
REDIS
# ユーザーの興味タグ(スコアは興味レベル)
ZADD user:1:interests 100 "redis"
ZADD user:1:interests 80 "database"
ZADD user:1:interests 60 "cache"
# ユーザーの最も興味があるタグを取得
ZREVRANGE user:1:interests 0 4 WITHSCORES
ユースケース5:試験ランキング
REDIS
# 学生のスコア
ZADD exam:math 95 "student:1"
ZADD exam:math 88 "student:2"
ZADD exam:math 92 "student:3"
# スコアランキングを取得
ZREVRANGE exam:math 0 -1 WITHSCORES
# 学生のランクを取得
ZREVRANK exam:math "student:1"
Sorted Setのエンコーディング最適化
Redisはソート済みセットのサイズに基づいてエンコーディングを自動的に選択します:
| エンコーディング | 条件 | 説明 |
|---|---|---|
| ziplist | 要素 <= 128、要素の長さ <= 64バイト | 圧縮リスト、メモリ節約 |
| skiplist | 要素 > 128 または 要素の長さ > 64バイト | スキップリスト + ハッシュテーブル、パフォーマンス向上 |
エンコーディングタイプの確認
REDIS
ZADD small:zset 1 "a" 2 "b" 3 "c"
OBJECT ENCODING small:zset
"ziplist"
# 多くの要素を追加した後
OBJECT ENCODING large:zset
"skiplist"
❓ よくある質問
Q Sorted SetとSetの違いは何ですか?
A Sorted Setのすべての要素はスコアを持ち、それでソートされます。Setは順序がありません。Sorted Setはリーダーボードやランキングのシナリオに最適です。
Q スコアは小数にできますか?
A はい。スコアは倍精度浮動小数点数で、小数をサポートします。
Q ZRANKはランクを0から返しますか、1から返しますか?
A 0からです。1位のランクは0、2位のランクは1です。
Q 最も高いスコアを持つ要素を取得するにはどうすればよいですか?
A
ZREVRANGE key 0 0 または ZRANGE key -1 -1 を使用します。Q 要素は重複できますか?
A いいえ。要素は一意ですが、スコアは重複可能です。
📖 まとめ
- Sorted Setはスコアを持つセットで、要素はスコアでソートされる
- ZADDで要素を追加、ZSCOREでスコアを取得
- ZRANK/ZREVRANKでランクを取得(低→高 / 高→低)
- ZRANGE/ZREVRANGEでランク範囲で要素を取得
- ZCARDで要素数を取得、ZCOUNTでスコア範囲内の要素をカウント
- ZREMで要素を削除、ZINCRBYでスコアを増加
- Sorted Setの応用:リーダーボード、トレンド、遅延キュー、ランキング
📝 練習問題
- リーダーボード: Sorted Setを使用してゲームリーダーボードを実装し、スコアを更新、ランクを表示、トップ10を取得しましょう
- トレンドリスト: トレンド検索リストを実装し、熱度スコアを更新、トレンドを表示、熱度を増加しましょう
- 試験ランキング: 学生のスコアをSorted Setに保存し、ランキングとスコアを表示しましょう
- 遅延キュー: Sorted Setを使用して遅延タスクキューを実装し、タスクを追加、期限切れのタスクを取得しましょう
次のレッスン
次のレッスンでは、Redis Sorted Sets(パート2)について学びます。高度なソート済みセット操作を解説します。



