Redis Lists(パート1)
Listは順序付けられた、重複可能な文字列のシーケンスです。このレッスンでは、基本的なリスト操作について解説します。
Listとは
Listは以下のものに似ています:
- Pythonのlist
- JavaScriptのArray
- JavaのLinkedList
Redisのリストの特徴:
- 順序付け:要素は挿入順序を保持します
- 重複可能:同じ値が複数回出現できます
- 両端操作:両端からの挿入とポップが可能です
mylist
├─ "element1"
├─ "element2"
├─ "element3"
└─ "element4"
💡 内部実装: Redisのリストはquicklistを使用しています。これは双方向リンクリストとziplistの組み合わせで、メモリとパフォーマンスのバランスを取ります。
LPUSHとRPUSH:要素の挿入
LPUSH:左側(先頭)から挿入
REDIS
# 左側から単一の要素を挿入
LPUSH mylist "world"
(integer) 1 # リストの長さを返す
# 左側から複数の要素を挿入
LPUSH mylist "hello"
(integer) 2
# リストを表示
LRANGE mylist 0 -1
1) "hello"
2) "world"
⚠️ 補足: LPUSHで複数の要素を挿入する場合、パラメータの順に左から右へ挿入されます。
LPUSH mylist a b c の結果は [c, b, a, ...] となります。
RPUSH:右側(末尾)から挿入
REDIS
# 右側から挿入
RPUSH mylist "Redis"
(integer) 3
RPUSH mylist "Tutorial"
(integer) 4
# リストを表示
LRANGE mylist 0 -1
1) "hello"
2) "world"
3) "Redis"
4) "Tutorial"
LPUSHXとRPUSHX:リストが存在する場合のみ挿入
REDIS
# リストが存在しない場合は挿入失敗
LPUSHX notexist "value"
(integer) 0
# リストが存在する場合は挿入成功
LPUSHX mylist "first"
(integer) 5
RPUSHX mylist "last"
(integer) 6
LPOPとRPOP:要素のポップ
LPOP:左側(先頭)からポップ
REDIS
# 現在のリストを表示
LRANGE mylist 0 -1
1) "first"
2) "hello"
3) "world"
4) "Redis"
5) "Tutorial"
6) "last"
# 左側からポップ
LPOP mylist
"first"
# 複数の要素をポップ(Redis 6.2+)
LPOP mylist 2
1) "hello"
2) "world"
RPOP:右側(末尾)からポップ
REDIS
# 右側からポップ
RPOP mylist
"last"
# 複数の要素をポップ(Redis 6.2+)
RPOP mylist 2
1) "Tutorial"
2) "Redis"
リストが空の場合
REDIS
LPOP emptylist
(nil) # 空のリストはnilを返す
LLEN:リストの長さを取得
REDIS
LPUSH mylist "a" "b" "c"
LLEN mylist
(integer) 3
# リストが存在しない場合
LLEN notexist
(integer) 0
LRANGE:範囲内の要素を取得
LRANGEは最も一般的なリストクエリコマンドです。
基本的な使用方法
REDIS
LPUSH mylist "one" "two" "three" "four" "five"
# すべての要素を取得
LRANGE mylist 0 -1
1) "five"
2) "four"
3) "three"
4) "two"
5) "one"
# 最初の3つの要素を取得
LRANGE mylist 0 2
1) "five"
2) "four"
3) "three"
# 最後の2つの要素を取得
LRANGE mylist -2 -1
1) "two"
2) "one"
# インデックス1から3の要素を取得
LRANGE mylist 1 3
1) "four"
2) "three"
3) "two"
インデックスルール
| インデックス | 説明 |
|---|---|
| 0 | 最初の要素 |
| 1 | 2番目の要素 |
| -1 | 最後の要素 |
| -2 | 最後から2番目の要素 |
| 0 -1 | すべての要素 |
⚠️ 補足: LRANGEの終了インデックスは含まれます。
LRANGE 0 2 はインデックス0、1、2の要素を返します(合計3要素)。
Listを使用したキューとスタックの実装
キュー(FIFO:先入れ先出し)
RPUSH + LPOPを使用:
REDIS
# プロデューサー:右側からエンキュー
RPUSH queue:task "task1"
RPUSH queue:task "task2"
RPUSH queue:task "task3"
# コンシューマー:左側からデキュー
LPOP queue:task
"task1"
LPOP queue:task
"task2"
エンキュー → [task1, task2, task3] → デキュー
RPUSH LPOP
スタック(LIFO:後入れ先出し)
LPUSH + LPOPを使用:
REDIS
# プッシュ
LPUSH stack:data "item1"
LPUSH stack:data "item2"
LPUSH stack:data "item3"
# ポップ
LPOP stack:data
"item3"
LPOP stack:data
"item2"
プッシュ → [item3, item2, item1] → ポップ
LPUSH LPOP
💡 覚え方:
- キュー:RPUSH + LPOP(右から入れて左から出す)
- スタック:LPUSH + LPOP(左から入れて左から出す)
ブロッキングポップ:BLPOPとBRPOP
リストが空の場合、BLPOPとBRPOPは要素が利用可能になるか、タイムアウトが発生するまでブロックします。
BLPOP:ブロッキング左ポップ
REDIS
# クライアント1:キューでタスクを待つ(最大10秒)
BLPOP queue:task 10
# クライアント2:タスクを追加
RPUSH queue:task "new_task"
# クライアント1が受信:
1) "queue:task" # リスト名
2) "new_task" # ポップされた要素
BRPOP:ブロッキング右ポップ
REDIS
BRPOP queue:task 10
複数リストでのブロッキング
REDIS
# 複数のリストで待機、最初にデータがあるものを返す
BLPOP queue:high queue:low 10
💡 使用例: BLPOP/BRPOPはタスクキューやメッセージキューの実装によく使用され、コンシューマーが新しいタスクを待ってブロックします。
Listのユースケース
ユースケース1:メッセージキュー
REDIS
# プロデューサー:メッセージを送信
RPUSH queue:email '{"to":"user@example.com","subject":"Hello"}'
# コンシューマー:メッセージを受信(ブロッキング待機)
BLPOP queue:email 0
ユースケース2:最新リスト
REDIS
# 最新の記事を追加
LPUSH articles:latest "article:123"
LPUSH articles:latest "article:124"
LPUSH articles:latest "article:125"
# 最新の10記事を取得
LRANGE articles:latest 0 9
# リストを最大100記事に制限
LTRIM articles:latest 0 99
ユースケース3:タイムライン
REDIS
# 投稿を公開(ユーザータイムラインに追加)
LPUSH timeline:user:1 "post:1001"
LPUSH timeline:user:1 "post:1002"
# タイムラインを表示(最新20件)
LRANGE timeline:user:1 0 19
ユースケース4:操作ログ
REDIS
# ユーザーアクションを記録
RPUSH log:user:1 "login at 2026-06-23 10:00:00"
RPUSH log:user:1 "view article:123"
RPUSH log:user:1 "like article:123"
# 最近のアクションを表示
LRANGE log:user:1 -10 -1
LTRIM:リストのトリミング
LTRIMは指定された範囲内の要素を保持し、それ以外を削除します。
REDIS
LPUSH mylist "one" "two" "three" "four" "five"
# 最初の3要素のみ保持
LTRIM mylist 0 2
OK
LRANGE mylist 0 -1
1) "five"
2) "four"
3) "three"
使用例:固定サイズのリストを維持
REDIS
# 新しい記事を追加し、最大100件に制限
LPUSH articles:latest "article:new"
LTRIM articles:latest 0 99
💡 ヒント: LPUSH + LTRIM を組み合わせると、最新アイテムの上限付きリストを維持できます。
❓ よくある質問
Q Listの最大要素数は?
A 最大2^32 - 1(約42億)ですが、実際にはメモリによって制限されます。
Q LPUSHとRPOPの速度は?
A O(1)の時間複雑度で、非常に高速です。先頭と末尾の操作は定数時間です。
Q LRANGEの速度は?
A O(N)で、Nは返される要素数です。広い範囲を取得すると遅くなります。
Q BLPOPは無期限にブロックしますか?
A いいえ。タイムアウトを設定してください。タイムアウト後はnilを返します。タイムアウト0は永久待機を意味します。
Q リストの途中に挿入するには?
A LINSERTを使用しますが、O(N)のパフォーマンスです。先頭と末尾のみで操作することを推奨します。
📖 まとめ
- Listは順序付けられた、重複可能な文字列のシーケンス
- LPUSH/RPUSHで左と右から挿入、LPOP/RPOPで左と右からポップ
- LRANGEで範囲内の要素を取得、LLENで長さを取得
- RPUSH + LPOP = キュー(FIFO)
- LPUSH + LPOP = スタック(LIFO)
- BLPOP/BRPOPでブロッキングポップ、タスクキューに使用
- Listの応用:メッセージキュー、最新リスト、タイムライン、操作ログ
- LTRIMでリストをトリミングし、固定サイズを維持
📝 練習問題
- キューの実装: RPUSHとLPOPを使用してタスクキューを実装し、プロデューサーとコンシューマーをシミュレートしましょう
- スタックの実装: LPUSHとLPOPを使用してスタックを実装し、プッシュとポップをシミュレートしましょう
- 最新リスト: 最新記事リストを実装し、記事を追加して最大10件に制限しましょう
- ブロッキング待機: BLPOPを使用してブロッキングタスクキューを実装しましょう(2つのターミナルが必要)
次のレッスン
次のレッスンでは、Redis Lists(パート2)について学びます。クエリ、変更、高度なリスト操作を解説します。



