Redis Strings(パート2)

このレッスンでは、文字列の数値演算とビット演算について解説します。カウンターや統計などのユースケースを実現できます。

数値演算

Redisの文字列は整数を保存でき、アトミックな数値演算をサポートします。

INCRとDECR:インクリメントとデクリメント

REDIS
# 初期値を設定
SET counter 10

# 1増加
INCR counter
(integer) 11

# 1減少
DECR counter
(integer) 10
💡 アトミック性: INCRとDECRはアトミックな操作です。複数のクライアントが同時にINCRを実行しても競合が発生しないため、カウンターに最適です。

INCRBYとDECRBY:増加量を指定

REDIS
SET counter 100

# 10増加
INCRBY counter 10
(integer) 110

# 20減少
DECRBY counter 20
(integer) 90

INCRBYFLOAT:浮動小数点演算

REDIS
SET price 10.5

# 2.3増加
INCRBYFLOAT price 2.3
"12.8"

# 1.5減少(負の数を渡す)
INCRBYFLOAT price -1.5
"11.3"
⚠️ 補足: INCRBYFLOATは浮動小数点数を文字列形式で返します。整数ではありません。

数値演算の制限

REDIS
# 数値以外の文字列に対する操作は失敗
SET text "hello"
INCR text
(error) ERR value is not an integer or out of range

# 存在しないキーに対する操作(0から開始)
INCR newcounter
(integer) 1  # 0から1に増加

使用例:カウンター

REDIS
# 記事の閲覧数
INCR article:123:views
(integer) 1

# ユーザーのいいね数
INCR user:456:likes
(integer) 1

# API呼び出し数
INCR api:usage:20260623
(integer) 1

範囲操作

GETRANGE:部分文字列を取得

REDIS
SET message "Hello Redis World"

# 最初の5文字を取得
GETRANGE message 0 4
"Hello"

# 中間部分を取得
GETRANGE message 6 10
"Redis"

# 最後の5文字を取得
GETRANGE message -5 -1
"World"

# 文字列全体を取得
GETRANGE message 0 -1
"Hello Redis World"
💡 インデックスルール:

  • インデックスは0から始まります
  • 終了位置は含まれます
  • 負のインデックスは末尾からカウントします(-1は最後の文字)

SETRANGE:部分文字列を置換

REDIS
SET message "Hello World"

# 位置6から置換
SETRANGE message 6 "Redis"
(integer) 11  # 文字列の長さを返す

GET message
"Hello Redis"

# 元の長さを超えて置換(自動的に埋められる)
SET short "Hi"
SETRANGE short 5 "There"
(integer) 10

GET short
"Hi\x00\x00\x00There"  # 間にnullバイトで埋められる
⚠️ 補足: SETRANGEが元の文字列の長さを超える場合、隙間はnullバイト(\x00)で埋められます。

ビット操作

Redisの文字列はビット操作をサポートしており、ブルームフィルターやビットマップ統計などに役立ちます。

SETBITとGETBIT:ビットの設定と取得

REDIS
# ビットマップを設定(初期はすべて0)
SETBIT mybitmap 0 1
(integer) 0  # 古い値を返す

SETBIT mybitmap 2 1
(integer) 0

SETBIT mybitmap 7 1
(integer) 0

# ビット値を取得
GETBIT mybitmap 0
(integer) 1

GETBIT mybitmap 1
(integer) 0

GETBIT mybitmap 2
(integer) 1

BITCOUNT:1に設定されたビットをカウント

REDIS
# すべてのビットをカウント
BITCOUNT mybitmap
(integer) 3  # 3ビットが1に設定されている

# バイト範囲内でカウント
BITCOUNT mybitmap 0 0
(integer) 3  # バイト0には3ビットが1に設定されている

BITOP:ビット演算

REDIS
# 2つのビットマップを作成
SETBIT bitmap1 0 1
SETBIT bitmap1 1 1
SETBIT bitmap2 1 1
SETBIT bitmap2 2 1

# AND
BITOP AND result bitmap1 bitmap2
(integer) 1

GETBIT result 1
(integer) 1  # 両方でビット1のみが1

# OR
BITOP OR result bitmap1 bitmap2
(integer) 1

# XOR
BITOP XOR result bitmap1 bitmap2
(integer) 1

# NOT(1つのキーのみサポート)
BITOP NOT result bitmap1
(integer) 1

BITPOS:最初の0または1の位置を検索

REDIS
SET mykey "\xff\xf0\x00"  # バイナリ:11111111 11110000 00000000

# 最初の0を検索
BITPOS mykey 0
(integer) 12  # ビット12が最初の0

# 最初の1を検索
BITPOS mykey 1
(integer) 0  # ビット0が最初の1

# バイト範囲内で検索
BITPOS mykey 1 1 2
(integer) 8  # バイト1-2内で、ビット8が最初の1

使用例:ユーザーのチェックイン

REDIS
# ユーザーID 123が2026年6月23日にチェックイン(年の174日目)
SETBIT user:123:signin:2026 174 1

# チェックイン済みか確認
GETBIT user:123:signin:2026 174
(integer) 1

# 年間の合計チェックイン数をカウント
BITCOUNT user:123:signin:2026
(integer) 50  # 50日間チェックイン

# 連続チェックインの確認(BITPOSとビジネスロジックが必要)

使用例:オンラインユーザー統計

REDIS
# ユーザー123がオンライン
SETBIT online:users 123 1

# ユーザー456がオンライン
SETBIT online:users 456 1

# オンラインユーザー数をカウント
BITCOUNT online:users
(integer) 2

# ユーザー123がオフライン
SETBIT online:users 123 0

実用的なStringのヒント

1. 一意なIDの生成

REDIS
# INCRを使用して自動インクリメントIDを生成
SET next:user:id 1000

INCR next:user:id
(integer) 1001  # 新しいユーザーID

INCR next:user:id
(integer) 1002

2. レート制限カウンター

REDIS
# APIレート制限:1分間に最大100回
SET limit:api:user:1 0 EX 60

INCR limit:api:user:1
(integer) 1

# 制限を超えたか確認
GET limit:api:user:1
"50"  # 現在50回呼び出し

3. 分散シーケンス番号

REDIS
# 注文番号の生成
SET order:sequence 1000000000

INCR order:sequence
(integer) 1000000001  # 新しい注文番号

4. UV(ユニークビジター)統計

REDIS
# ビットマップを使用したUV統計
SETBIT uv:20260623 12345 1  # ユーザーID 12345が訪問
SETBIT uv:20260623 67890 1  # ユーザーID 67890が訪問

# UVをカウント
BITCOUNT uv:20260623
(integer) 2  # 2人のユニークビジター

パフォーマンス最適化のヒント

1. バッチ操作の使用

REDIS
# ❌ 複数の個別操作
SET key1 "value1"
SET key2 "value2"
SET key3 "value3"

# ✅ バッチ操作
MSET key1 "value1" key2 "value2" key3 "value3"

2. 適切な有効期限の設定

REDIS
# キャッシュデータに有効期限を設定
SET cache:key "value" EX 3600

# キャッシュ雪崩を回避:TTLにランダムなジッターを追加
SET cache:key "value" EX 3600

3. 適切なエンコーディングの選択

REDIS
# 短い文字列はembstrエンコーディングを使用(<= 44バイト)
SET short "Hello Redis"

# 長い文字列はrawエンコーディングを使用
SET long "This is a very long string..."

# エンコーディングを確認
OBJECT ENCODING short
"embstr"

❓ よくある質問

Q INCRはオーバーフローしますか?
A はい。Redisの整数は64ビットの符号付き整数です(範囲:-2^63 〜 2^63-1)。範囲外になるとエラーが返ります。
Q 浮動小数点カウンターを実装するにはどうすればよいですか?
A INCRBYFLOATコマンドを使用しますが、文字列形式を返すことに注意してください。
Q ビット操作の実用的な用途は何ですか?
A ビットマップは、ユーザーのチェックイン、オンラインユーザー統計、ブルームフィルター、権限ビットなどに使用できます。非常にメモリ効率が良いです。
Q GETRANGEの時間複雑度は?
A O(N)で、Nは返される部分文字列の長さです。短い部分文字列の取得は非常に高速です。
Q 大きなテキスト(記事の内容など)を保存するにはどうすればよいですか?
A まず圧縮するか、シャーディングすることを検討してください。より良い方法は、ファイルシステムやオブジェクトストレージに保存し、RedisにはURLのみを保持することです。

📖 まとめ

📝 練習問題

  1. カウンター: 記事の閲覧カウンターを実装し、10回の閲覧をシミュレートして最終カウントを確認しましょう
  2. 範囲操作: 長い文字列を設定し、GETRANGEを使用して異なる部分を取得しましょう
  3. ビットマップチェックイン: ビットマップを使用してユーザーのチェックインを実装し、チェックイン日数をカウントしましょう
  4. UV統計: ビットマップを使用してWebサイトのUVを追跡し、複数のユーザー訪問をシミュレートしましょう

次のレッスン

次のレッスンでは、Redis Hashes(パート1)について学びます。基本的なハッシュ操作を解説します。

100%