Redis Hashes(パート2)
このレッスンでは、ハッシュフィールドの数値演算、反復クエリ、およびその他の高度な機能について解説します。
HINCRBY:フィールド値の増加
ハッシュフィールドは数値文字列を保存でき、アトミックな算術演算をサポートします。
HINCRBY:整数の増加
REDIS
# 記事統計を作成
HSET article:123 views 1000 likes 50 comments 20
# 閲覧数を増加
HINCRBY article:123 views 1
(integer) 1001
# いいね数を増加
HINCRBY article:123 likes 1
(integer) 51
# バッチ増加
HINCRBY article:123 views 10
(integer) 1011
# 減少(負の数を渡す)
HINCRBY article:123 likes -1
(integer) 50
HINCRBYFLOAT:浮動小数点の増加
REDIS
# 商品価格
HSET product:2001 price 99.99
# 価格を上げる
HINCRBYFLOAT product:2001 price 10.5
"110.49"
# 価格を下げる(負の数を渡す)
HINCRBYFLOAT product:2001 price -5.0
"105.49"
使用例:カウンターグループ
REDIS
# ユーザー統計
HSET user:stats:1 posts 0 followers 0 following 0
# 記事を公開
HINCRBY user:stats:1 posts 1
# フォロワーを獲得
HINCRBY user:stats:1 followers 1
# フォローする
HINCRBY user:stats:1 following 1
# 統計を表示
HGETALL user:stats:1
💡 利点: Hashを使用して複数のカウンターを保存すると、複数のStringキーを使用するよりもメモリ効率が良いです。
HSCAN:大きなハッシュの反復処理
ハッシュに多くのフィールドがある場合、HGETALLは一度にすべてのデータを返すため、サーバーをブロックする可能性があります。HSCANを使用すると、バッチ反復処理が可能です。
基本的な使用方法
REDIS
# 大きなハッシュを作成
HSET large:hash field1 "value1" field2 "value2" ... field1000 "value1000"
# 反復処理を開始
HSCAN large:hash 0
1) "127" # 次の反復処理のカーソル
2) 1) "field1"
2) "value1"
3) "field2"
4) "value2"
...
# 反復処理を続行
HSCAN large:hash 127
1) "0" # カーソルが0の場合は反復処理完了
2) 1) "field999"
2) "value999"
...
パターンマッチ
REDIS
# パターンに一致するフィールドのみを取得
HSCAN user:1 0 MATCH age*
1) "0"
2) 1) "age"
2) "25"
反復処理ごとの件数を指定
REDIS
# 反復処理ごとに約100フィールドを返す
HSCAN large:hash 0 COUNT 100
💡 使用例: HSCANは、サーバーをブロックせずに大きなハッシュを反復処理するのに最適です。
高度なHashアプリケーション
ユースケース1:eコマース商品詳細
REDIS
# 完全な商品情報を保存
HSET product:3001 \
name "iPhone 15 Pro" \
brand "Apple" \
price 8999 \
stock 100 \
category "phone" \
sales 0 \
rating 4.8
# 商品の基本情報を表示
HMGET product:3001 name price stock
# 販売数を増加
HINCRBY product:3001 sales 1
# 在庫を減少
HINCRBY product:3001 stock -1
# 評価を更新
HSET product:3001 rating 4.9
# 在庫を確認
HGET product:3001 stock
ユースケース2:ユーザー設定
REDIS
# ユーザー設定を保存
HSET user:config:1 \
theme "dark" \
language "en" \
notifications "on" \
privacy "public" \
timezone "America/New_York"
# 単一の設定を取得
HGET user:config:1 theme
# 設定を変更
HSET user:config:1 theme "light"
# バッチで設定を取得
HMGET user:config:1 theme language notifications
ユースケース3:リアルタイム統計
REDIS
# 日次サイト統計
HSET stats:20260623 \
page_views 0 \
unique_visitors 0 \
new_users 0 \
orders 0 \
revenue 0.0
# ページビューを増加
HINCRBY stats:20260623 page_views 1
# ユニークビジターを増加
HINCRBY stats:20260623 unique_visitors 1
# 注文数を増加
HINCRBY stats:20260623 orders 1
# 収益を増加
HINCRBYFLOAT stats:20260623 revenue 299.99
# 統計を表示
HGETALL stats:20260623
ユースケース4:A/Bテスト設定
REDIS
# 実験設定を保存
HSET experiment:homepage \
button_color "blue" \
layout "grid" \
show_banner "yes" \
discount_rate 0.1
# 実験設定を取得
HGET experiment:homepage button_color
# 実験設定を更新
HSET experiment:homepage button_color "red"
HashとJSONの比較
ストレージ比較
方法1:Hash
REDIS
HSET user:1 name "Alice" age 25 email "alice@example.com"
方法2:String + JSON
REDIS
SET user:1 '{"name":"Alice","age":25,"email":"alice@example.com"}'
操作比較
| 操作 | Hash | String JSON |
|---|---|---|
| 単一フィールド取得 | HGET user:1 name |
JSONを解析する必要がある |
| 単一フィールド変更 | HSET user:1 age 26 |
読取→解析→変更→シリアル化→書き戻し |
| 全フィールド取得 | HGETALL user:1 |
GET user:1 + JSON解析 |
| 数値演算 | HINCRBY user:1 age 1 |
解析→変更→シリアル化が必要 |
| メモリ使用量 | 少ない | 多い(JSON形式のオーバーヘッド) |
ユースケース比較
| シナリオ | 推奨 | 理由 |
|---|---|---|
| ユーザープロフィール | Hash | 独立したフィールド、頻繁な更新 |
| 商品情報 | Hash | 独立したフィールド、部分更新 |
| 複雑なネストオブジェクト | String JSON | Hashはネストをサポートしない |
| 配列データ | String JSON | Hashは配列をサポートしない |
| 設定オブジェクト | Hash | 独立したフィールド、高速クエリ |
💡 選択原則:
- 独立したフィールド、頻繁な部分更新 → Hash
- 複雑なネスト、配列が必要 → String JSON
- 数値演算が必要 → Hash
パフォーマンス最適化
1. 大きなハッシュを避ける
REDIS
# ❌ 推奨されない:単一のハッシュにフィールドが多すぎる
HSET big:hash field1 ... field10000
# ✅ 推奨:複数のハッシュに分割
HSET hash:part1 field1 ... field1000
HSET hash:part2 field1001 ... field2000
2. HGETALLの代わりにHSCANを使用
REDIS
# ❌ 大きなハッシュでHGETALLを使用
HGETALL large:hash # ブロックする可能性がある
# ✅ HSCANで反復処理
HSCAN large:hash 0
3. バッチ操作でネットワークラウンドトリップを削減
REDIS
# ❌ 複数の個別操作
HSET user:1 name "Alice"
HSET user:1 age 25
HSET user:1 city "Beijing"
# ✅ バッチ操作
HSET user:1 name "Alice" age 25 city "Beijing"
4. エンコーディングしきい値の設定
redis.conf内:
CONF
# ハッシュフィールド数のしきい値(デフォルト512)
hash-max-ziplist-entries 512
# ハッシュフィールド値の最大長(デフォルト64バイト)
hash-max-ziplist-value 64
ℹ️ 補足: しきい値を上げるとメモリを節約できますが、パフォーマンスが低下する可能性があります。実際のデータに基づいて調整してください。
Hashの制限
1. ネストのサポートなし
REDIS
# ❌ ネストされたオブジェクトを直接保存できない
HSET user:1 address '{"city":"Beijing","zip":"100000"}'
# ✅ ネスト部分には文字列を使用
HSET user:1 city "Beijing" zip "100000"
2. 配列のサポートなし
REDIS
# ❌ 配列を保存できない
HSET user:1 tags ["redis","database","cache"]
# ✅ 配列にはセットまたはリストを使用
SADD user:1:tags "redis" "database" "cache"
3. 値は文字列のみ
REDIS
# すべての値は文字列
HSET user:1 age 25
HGET user:1 age
"25" # 整数ではなく文字列を返す
❓ よくある質問
Q HINCRBYを数値以外のフィールドで使用するとどうなりますか?
A エラーが返ります:
(error) ERR hash value is not an integer。フィールド値が数値文字列であることを確認してください。Q Hashのフィールドは順序付けられていますか?
A いいえ。Hashのフィールドは順序なしです。HGETALLは特定の順序を保証しません。
Q キーがHash型かどうかを確認するにはどうすればよいですか?
A TYPEコマンドを使用します:
TYPE user:1 は hash を返します。Q HSCANは重複がないことを保証しますか?
A いいえ。HSCANは重複フィールドを返す可能性があります。アプリケーション層で重複排除を処理する必要があります。
Q HashとSetの違いは何ですか?
A Hashはフィールドと値のペアを保存し、Setは一意な要素を保存します。Hashはオブジェクト用、Setはタグや関係用です。
📖 まとめ
- HINCRBY/HINCRBYFLOATでフィールドの数値演算を実行
- HSCANで大きなハッシュを反復処理し、ブロックを回避
- Hashは商品、設定、統計オブジェクトに適している
- HashとJSON文字列:部分更新が必要なシンプルなオブジェクトにはHash
- パフォーマンスのヒント:大きなハッシュを避け、HSCANを使用し、バッチ操作を行う
- Hashの制限:ネストなし、配列なし、値は文字列のみ
📝 練習問題
- 数値演算: Hashを使用して記事統計(閲覧数、いいね数、コメント数)を保存し、HINCRBYで増加させましょう
- 商品管理: Hashで商品情報を保存し、表示、変更、販売数の増加、在庫の減少を練習しましょう
- 設定管理: Hashでユーザー設定を保存し、単一設定の取得、バッチ取得、設定の変更を練習しましょう
- パフォーマンス比較: HashとString JSONで単一フィールドを変更する手順を比較しましょう
次のレッスン
次のレッスンでは、Redis Lists(パート1)について学びます。基本的なリスト操作を解説します。



