Redis Hashes(パート1)
Hashはキーと値のコレクションで、オブジェクトの保存に最適です。このレッスンでは、基本的なハッシュ操作について解説します。
Hashとは
Hashは以下のものに似ています:
- Pythonのdict
- JavaScriptのObject
- JavaのHashMap
単一のRedisハッシュキーは複数のフィールドと値のペアを保存できます:
user:1
├─ name → "Alice"
├─ age → "25"
├─ city → "Beijing"
└─ email → "alice@example.com"
💡 利点: Hashを使用すると、オブジェクト全体を読み取らずに個々のフィールドを変更できます。また、JSON文字列を保存するよりもメモリ効率が良いです。
HSETとHGET:フィールドの設定と取得
HSET:単一フィールドの設定
REDIS
# 単一フィールドの設定
HSET user:1 name "Alice"
(integer) 1 # 新しく追加されたフィールドの数を返す
# 複数フィールドの設定
HSET user:1 age 25 city "Beijing"
(integer) 2 # 2つの新しいフィールドを追加
# 既存フィールドの更新
HSET user:1 name "Bob"
(integer) 0 # フィールドは既に存在する、0を返す
HGET:単一フィールドの取得
REDIS
HGET user:1 name
"Alice"
HGET user:1 age
"25"
# フィールドが存在しない場合
HGET user:1 notexist
(nil)
HSETNX:フィールドが存在しない場合のみ設定
REDIS
# フィールドが存在しない場合のみ設定
HSETNX user:1 name "Charlie"
(integer) 0 # フィールドは既に存在、失敗
HSETNX user:1 phone "13800138000"
(integer) 1 # フィールドは存在しない、設定成功
HMSETとHMGET:バッチ操作
HMSET:バッチフィールド設定
REDIS
HMSET user:2 name "Bob" age 30 city "Shanghai" email "bob@example.com"
OK
⚠️ 補足: Redis 4.0.0以降、HMSETは非推奨です。複数フィールドを設定するにはHSETを使用してください。
HMGET:バッチフィールド取得
REDIS
HMGET user:2 name age city
1) "Bob"
2) "30"
3) "Shanghai"
# 存在しないフィールドを含む場合
HMGET user:2 name email phone
1) "Bob"
2) "bob@example.com"
3) (nil) # phoneは存在しない
HGETALL:すべてのフィールドと値を取得
REDIS
HGETALL user:2
1) "name"
2) "Bob"
3) "age"
4) "30"
5) "city"
6) "Shanghai"
7) "email"
8) "bob@example.com"
⚠️ 補足: HGETALLはフィールド名と値の交互の配列を返します。ハッシュが大きい場合、大量のメモリとネットワーク帯域幅を使用します。注意して使用してください!
HKEYSとHVALS:すべてのフィールド名または値を取得
HKEYS:すべてのフィールド名を取得
REDIS
HKEYS user:2
1) "name"
2) "age"
3) "city"
4) "email"
HVALS:すべての値を取得
REDIS
HVALS user:2
1) "Bob"
2) "30"
3) "Shanghai"
4) "bob@example.com"
HEXISTS:フィールドの存在確認
REDIS
HEXISTS user:2 name
(integer) 1 # 存在する
HEXISTS user:2 phone
(integer) 0 # 存在しない
HDEL:フィールドの削除
REDIS
# 単一フィールドの削除
HDEL user:2 email
(integer) 1 # 1つのフィールドを削除
# 複数フィールドの削除
HDEL user:2 age city
(integer) 2 # 2つのフィールドを削除
# 存在しないフィールドの削除
HDEL user:2 notexist
(integer) 0
HLEN:フィールド数を取得
REDIS
HSET user:3 name "Charlie" age 28
HLEN user:3
(integer) 2 # 2つのフィールドがある
# キーが存在しない場合
HLEN notexist
(integer) 0
HSTRLEN:フィールド値の長さを取得
REDIS
HSET user:1 name "Alice" bio "Software Engineer"
HSTRLEN user:1 name
(integer) 5 # "Alice"の長さは5
HSTRLEN user:1 bio
(integer) 17 # "Software Engineer"の長さは17
Hashのユースケース
ユースケース1:ユーザー情報の保存
REDIS
# ユーザーの基本情報を保存
HSET user:1001 name "Alice" age 25 email "alice@example.com" role "admin"
# ユーザー名を取得
HGET user:1001 name
# ユーザー年齢を更新
HSET user:1001 age 26
# すべてのユーザー情報を取得
HGETALL user:1001
ユースケース2:ショッピングカート
REDIS
# ユーザー1のショッピングカート
HSET cart:user:1 product:101 2 # 商品101、数量2
HSET cart:user:1 product:102 1 # 商品102、数量1
HSET cart:user:1 product:103 5 # 商品103、数量5
# カート内のすべての商品を表示
HGETALL cart:user:1
# 商品数量を更新
HSET cart:user:1 product:101 3
# 商品を削除
HDEL cart:user:1 product:102
# カート内の商品数を確認
HLEN cart:user:1
ユースケース3:記事メタデータ
REDIS
# 記事情報を保存
HSET article:123 title "Redis Tutorial" author "Alice" views 1000 likes 50
# 閲覧数を増加(HINCRBYが必要)
HINCRBY article:123 views 1
# いいね数を増加
HINCRBY article:123 likes 1
# 記事のタイトルと著者を取得
HMGET article:123 title author
ユースケース4:商品キャッシュ
REDIS
# 商品詳細をキャッシュ
HSET product:2001 name "iPhone 15" price 5999 stock 100 category "phone"
# 商品価格を取得
HGET product:2001 price
# 在庫を更新
HSET product:2001 stock 95
# 商品が存在するか確認
HEXISTS product:2001 name
オブジェクト保存におけるHashとStringの比較
方法1:String + JSON
REDIS
SET user:1 '{"name":"Alice","age":25,"email":"alice@example.com"}'
# オブジェクト全体を取得
GET user:1
# 年齢を変更:読み取り、解析、変更、シリアル化、書き戻しが必要
# 複数ステップ、非効率
方法2:Hash
REDIS
HSET user:1 name "Alice" age 25 email "alice@example.com"
# 単一フィールドを取得
HGET user:1 name
# 年齢を変更:1ステップの操作
HSET user:1 age 26
# 複数フィールドを取得
HMGET user:1 name age
比較まとめ
| 項目 | String(JSON) | Hash |
|---|---|---|
| 単一フィールドの変更 | オブジェクト全体の読み取りが必要 | 直接変更可能 |
| メモリ使用量 | 多い(JSON形式のオーバーヘッド) | 少ない(コンパクトな保存) |
| 単一フィールドのクエリ | JSONの解析が必要 | 直接アクセス |
| 複雑なネストオブジェクト | ✅ サポート | ❌ 非サポート |
| 部分更新 | ❌ 困難 | ✅ 簡単 |
💡 選択ガイド:
- シンプルなオブジェクト(フラット構造):Hashを使用
- 複雑なオブジェクト(ネスト構造):String + JSONを使用
- 個々のフィールドを頻繁に変更する場合:Hashを使用
Hashのエンコーディング最適化
Redisはハッシュのサイズに基づいてエンコーディングを自動的に選択します:
| エンコーディング | 条件 | 説明 |
|---|---|---|
| ziplist | フィールド <= 512、値の長さ <= 64バイト | 圧縮リスト、メモリ節約 |
| hashtable | フィールド > 512 または 値の長さ > 64バイト | ハッシュテーブル、パフォーマンス向上 |
エンコーディングタイプの確認
REDIS
HSET small:hash field1 "value1" field2 "value2"
OBJECT ENCODING small:hash
"ziplist"
# 多くのフィールドを追加した後
HSET large:hash field1 "value1" field2 "value2" ... field600 "value600"
OBJECT ENCODING large:hash
"hashtable"
ℹ️ 補足: エンコーディングはRedisによって自動的に選択されます。設定パラメータでしきい値を調整できます。
❓ よくある質問
Q Hashにはいくつのフィールドを保存できますか?
A 理論上は無制限(2^32 - 1)ですが、実際にはメモリによって制限されます。個々のハッシュは数千フィールド以下に抑えることを推奨します。
Q HGETALLはパフォーマンスに影響しますか?
A はい。ハッシュが大きい場合、HGETALLは大量のデータを返し、メモリと帯域幅を消費します。反復取得にはHSCANを使用してください。
Q Hashのフィールド値は数値にできますか?
A はい。Redisのすべての値は文字列ですが、数値文字列は算術演算(HINCRBY)をサポートします。
Q ハッシュキー全体を削除するにはどうすればよいですか?
A フィールドを削除するHDELではなく、キーを削除するDELを使用します:
DEL user:1。Q Hashはネストをサポートしますか?
A いいえ。Hashの値は文字列のみです。ネストが必要な場合は、String + JSONを使用してください。
📖 まとめ
- Hashはキーと値のコレクションで、オブジェクトの保存に最適
- HSET/HGETで個々のフィールドを設定および取得
- HMSET/HMGETでバッチフィールド操作
- HGETALLですべてのフィールドと値を取得(注意して使用)
- HKEYS/HVALSですべてのフィールド名または値を取得
- HEXISTSでフィールドの存在確認、HDELでフィールド削除、HLENでフィールド数取得
- Hashはユーザー情報、ショッピングカート、記事メタデータの保存に最適
- シンプルなオブジェクトにはHash、複雑なネストオブジェクトにはString + JSONを使用
📝 練習問題
- ユーザー情報: Hashを使用してユーザー情報(名前、年齢、メール、都市)を保存し、すべての情報を取得しましょう
- ショッピングカート: Hashでショッピングカートを実装し、3つの商品を追加、1つの数量を変更、1つの商品を削除しましょう
- フィールド操作: HEXISTSでフィールドの存在を確認し、HLENでフィールドをカウントしましょう
- 比較練習: 同じオブジェクトをString + JSONとHashの両方で保存し、単一フィールドを変更する手順を比較しましょう
次のレッスン
次のレッスンでは、Redis Hashes(パート2)について学びます。高度なハッシュ操作と数値計算を解説します。



