2013-01-18

Redis でインデックス的なものを使う

お手軽さとパフォーマンスの噂を聞いて Redis を使い始めたわけですが、RDB のようなクエリをしようとすると、当然、利用者側でなんとかする必要があります。たぶん、こうやればいいのかなぁという感じで。

クイズの回答を Redis に保存しようとしています。「各 user は、各 quiz に多くとも1つだけ回答できる。ただし、上書きができる。」という前提です。こんな JSON でデータを保存しましょう。

{"quiz": "1", "user": "alice", "ans": "X", ...}
{"quiz": "2", "user": "alice", "ans": "Y", ...}
{"quiz": "1", "user": "bob", "ans": "X", ...}


必要なクエリは以下のとおり。
  • quiz=1 に回答したユーザを取得する。
  • quiz=1 に、ans=X と回答したユーザを取得する。
  • user=alice の回答を取得する。

データ構造

データ本体を保持するハッシュ
quiz:1:user, alice => {...}

クイズ番号と回答の組み合わせごとのユーザを保持するセット
index:quiz:1:ans:X:users => (alice, bob)

ユーザが回答したクイズ番号を保持するセット
Index:user:alice:quizzes => (1, 2)


まず登録。以下、コードは redis-cli です。

> HSET quiz:1:user alice '{...}'
(integer) 1
> SADD index:quiz:1:answer:X:users alice
(integer) 1
> SADD index:user:alice:quizzes 1
(integer) 1

残りふたつの回答も同様に。

> HSET quiz:2:user alice '{...}'
> SADD index:quiz:2:answer:Y:users alice
> SADD index:user:alice:quizzes 2

> HSET quiz:1:user bob '{...}'
> SADD index:quiz:1:answer:X:users bob
> SADD index:user:bob:quizzes 1

クイズ番号とユーザ名から、任意の回答を取得できます。

> HGET quiz:1:user alice
"{...}"
quiz=1 の回答、回答数、および回答したユーザは、このハッシュから取り出します。
> HGETALL quiz:1:user
1) "alice"
2) "{…}"
3) "bob"
4) "{…}"
> HLEN quiz:1:user
(integer) 2
> HKEYS quiz:1:user
1) "alice"
2) "bob"
quiz=1 かつ ans=X の回答数、回答したユーザ、回答は index:quiz:1:answer:X:users セットから取り出します。
> SCARD index:quiz:1:answer:X:users
(integer) 2
> SMEMBERS index:quiz:1:answer:X:users
1) "alice"
2) "bob"
> HMGET quiz:1:user alice bob  # クイズ番号とユーザ名を使って、ハッシュから取得
1) "{…}"
2) "{…}"
user=alice の回答数、クイズ番号、回答は index:user:alice:quizzes セットから取得します。
> SCARD index:user:alice:quizzes
(integer) 2
> SMEMBERS index:user:alice:quizzes
1) "1"
2) "2"
> HGET quiz:1:user alice
"{…}"
削除するときには、ハッシュと2つのセットを削除します。
> HDEL quiz:1:user alice
(integer) 1
> SREM index:quiz:1:answer:X:users alice
(integer) 1
> SREM index:user:alice:quizzes 1
(integer) 1
と、こんなやりかたで考えています。筋がいいことを願う。