データベース
 Computer >> コンピューター >  >> プログラミング >> データベース

Redisのハッシュ徹底解説!基本コマンドから実践的な活用例まで

Redisのハッシュ徹底解説!基本コマンドから実践的な活用例まで

Redisのハッシュ(Hash)は、1つのキーの下に複数の「フィールドと値」のペアを関連付けて格納できるデータ構造です。フィールドも値も文字列として扱われ、データ構造全体だけでなく、構造内の個々のフィールド単位でも柔軟に変更できるのが大きな特徴です。この特性により、アプリケーション内のオブジェクトを保存するバックエンドストアとして、非常に高速かつ理想的な選択肢となります。

CLIで学ぶハッシュの基本操作

まずは、2つのフィールドを持つハッシュを作成してみましょう。

127.0.0.1:6379> HMSET my_hash key1 "foo" key2 "bar"
OK

ハッシュに関連付けられたすべてのフィールドと値を一覧表示します。

127.0.0.1:6379> HGETALL my_hash
1) "key1"
2) "foo"
3) "key2"
4) "bar"

既存フィールドの値を更新する例です。

127.0.0.1:6379> HSET my_hash key1 "xyzzy"
(integer) 0
127.0.0.1:6379> HGET my_hash key1
"xyzzy"

ハッシュから特定のフィールドだけを削除することも可能です。

127.0.0.1:6379> HDEL my_hash key2
(integer) 1
127.0.0.1:6379> HGETALL my_hash
1) "key1"
2) "xyzzy"

もちろん、ハッシュ自体を丸ごと削除することもできます。

127.0.0.1:6379> DEL my_hash
(integer) 1
127.0.0.1:6379> HGETALL my_hash
(empty list or set)

Redisの公式ドキュメントには、ハッシュで利用できるコマンドに関する詳細な情報が掲載されています。ここでは単にコマンドを羅列するのではなく、実際に楽しみながらハッシュの活用方法を見ていきましょう。

Dwemthy's Arrayで遊ぶ!ハッシュを使ったRPG実装

Dwemthy's Arrayは、Why the Lucky Stiff氏が名著『Why's (poignant) guide to Ruby』の中で書いた小さなロールプレイングゲーム(RPG)のサンプルです。Rubyのメタプログラミングを解説するために作られたものでしたが、今回は同じRPGのアイデアを、Redisのハッシュ(とリストを少し併用)で実装してみます。

配列に登場する各モンスターごとに、次のようなハッシュを作成します。

name: "AssistantViceTentacleAndOmbudsman"
life: 320
strength: 6
charisma: 144
weapon: 50

そして、配列の奥深くへ潜っていく様子がこちらです。

>>> import redis
>>> import dwemthy
>>> conn = redis.StrictRedis(host="localhost", port=6379)
>>> dw = dwemthy.Array.new(conn,
      {
        "name": "AssistantViceTentacleAndOmbudsman",
        "life": 320,
        "strength": 6,
        "charisma": 144,
        "weapon": 50
      }
    )
"[Get ready. AssistantViceTentacleAndOmbudsman has emerged!]"
>>> rabbit = dwemthy.Rabbit(dw)
>>> rabbit.sword()
"[You hit with 2 points of damage!]"
"[Your enemy hit with 10 points of damage!]"
"[Rabbit has died!]"

コード全体は dwemthy.py として公開しているので、ぜひ手元で動かしながら読み進めてみてください。

コードのポイント解説

まず、ユーザーがファクトリメソッドを使って配列を作成すると、必要なデータ構造をセットアップし、新しい dwemthy.Array オブジェクトを返します。

class Array(object):
    list_key = "dwemethys_array"

    ...

    @classmethod
    def new(cls, conn, *bad_guys):
        """ Create a new set of problems for our hero to boomerang! """

        conn.delete(cls.list_key)

        # Give each bad guy a cozy spot in the array!
        for bad_guy in bad_guys:
            key = uuid.uuid4()
            conn.hmset(key, bad_guy)
            conn.rpush(cls.list_key, key)

        dw_list = cls(conn)
        dw_list.next_enemy()
        return dw_list

ここで使われている conn.hmset が、敵キャラクターごとのハッシュを作成する部分です。ハッシュを作成した後、そのキーをRedisのリストにプッシュしています。このリストは、シンプルなキューとして機能します。

すべての敵をセットアップし終えたら、Array.next_enemy() メソッドで配列の先頭にいる敵を戦闘態勢に整えます。

class Array(object):    
    list_key = "dwemethys_array"

    ...

    def next_enemy(self):
        """ Bring out the next enemy for our rabbit to face! """

        # We're moving on!
        if self.current != None:
            self.conn.delete(self.current)

        enemy_key = self.conn.lpop(self.list_key)

        if enemy_key is None:
            # Like a boss!
            print "[Whoa.  You decimated Dwemthy's List!]"
        else:
            # Get the new enemy ready!
            self.current = enemy_key
            print "[Get ready. {} has emerged!]".format(self["name"])

最終行の self["name"] は、Arrayオブジェクトに __setitem____getitem__ メソッドを定義することで実現しています。これにより、ArrayオブジェクトをほぼPythonの辞書のように扱えるようになり、現在の敵が持つフィールドの取得や更新がとても簡単になります。

class Array(object):

    ...

    def __setitem__(self, key, value): 
        self.conn.hset(self.current, key, value)

    def __getitem__(self, key):
        value = self.conn.hget(self.current, key)

        # hashes only store strings!
        if key != "name":
            return int(value)

        return value

なお、コメントにもある通り、Redisのハッシュは文字列しか保存できないため、数値として扱いたい場合は int() による変換が必要になる点に注意しましょう。

まとめ

Redisのハッシュは、構造全体・個々のフィールドの両方を自在に操作できる多彩なコマンドを備えており、開発者はそれを活かして幅広い問題を解決できます。オブジェクトの保存、キューの実装、ゲームの状態管理など、応用範囲は非常に広いのです。この記事が、皆さんのプロジェクトでRedisハッシュを活用するヒントになれば幸いです。

  1. Redisのユースケース徹底解説:押さえておきたい代表的な活用シーン5選

    本記事は、2017年11月7日にObjectRocket.com/blogで公開された記事を翻訳・再編集したものです。 Redis™は、シンプルながら高速なインメモリデータストアとして、さまざまな場面で活用されています。この記事では、Redisの最も一般的なユースケースを5つ紹介し、それぞれの選択に影響する特性について解説します。 1. セッションキャッシュ Redisの最も分かりやすいユースケースのひとつが、セッションキャッシュとしての利用です。Memcachedなど他のセッションストアと比較した場合のRedisの大きな利点は、永続化機能を備えている点にあります。キャッシュは通常、整合性の

  2. Redisの代表的なユースケース5選:特徴と活用方法を徹底解説

    本記事では、Redisの最も一般的なユースケースと、それぞれの選択に関わる特性について詳しく解説します。1. セッションキャッシュRedisの最も分かりやすいユースケースの一つが、セッションキャッシュとしての利用です。Memcachedなど他のセッションストアと比較した場合のRedisの大きな利点は、永続化機能を備えている点にあります。キャッシュの整合性は通常ミッションクリティカルではありませんが、ショッピングカートのセッション情報がすべて消えてしまったら、ユーザーは決して喜ばないでしょう。幸い、ここ数年でRedisの人気が大きく高まったおかげで、セッションキャッシュにRedisを適切に活用す