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
と、こんなやりかたで考えています。筋がいいことを願う。

2013-01-14

2013年にやらないこと

Chikirinの日記に「来年の抱負) やらないことを3つ決めよう!」という記事があります。昨年末のですね。

ビジネスであれば、「アジア市場には出るけど、欧米には進出しない」と決めたり、「インフラビジネスはやるけど、個別商品は売らない」と決めることができるでしょう。

何かを選ぶということは、他のもの・ことを選ばないということです。とはいえ、意識しないと、優先順位の低いことを選んでしまって、高いことを選ぶ資源がなくなってしまうことがあります。

というわけで、2013年にやらないこと


  • 日帰りできないレース(トライアスロン中島大会は例外)
  • 時間のかかる栄養補給
  • 長時間のネットサーフィン

昨年は大阪でトライアスロンに出たりとかしてて、時間もお金もかかったのでした。というわけで、今年はレース控えめ、とくに遠方のレースには出ません。

栄養補給というのは、食事のことです。私にとって、食事は大きく分けて2種類あります。ひとつは生命活動、もうひとつはエンターテイメントです。前者はよっぽど苦痛でなければ味とかどうでもいいので、効率重視です。森博嗣の小説で「空中給油が理想」みたいな台詞がありましたが、そういう感じですね。

長時間のネットサーフィンというのは、Twitter や Facebook や Google+ をだらだら見るとか、メンション送り合ったりとかのことです。長時間の定義はまだわかりませんが、まずは5分(ポモドーロの休憩分)くらいをリミットにしてみようと考えています。

2013-01-06

Redis をさわりはじめました

Python で Redis を触ってみました。オートインクリメントやインデックス用のkeyを使うイディオムがある。

import json
import redis
r = redis.Redis()

def create_user(name, auth):
    uid = r.incr('global:next_uid')  # ユニークなIDを取得
    return put_user(uid, name, auth)

def get_user(uid):
    value = r.get('user:%s' % uid)
    if value:
        return json.loads(value)

def put_user(uid, name, auth):
    user = {'uid': uid, 'name': name, 'auth': auth}
    r.set('user:%s' % uid, json.dumps(user))
    r.set('index:user:auth:%s' % auth, uid)  # auth -> uid を引くため
    return user

def get_user_by_auth(auth):
    uid = r.get('index:user:auth:%s' % auth)
    if not uid:
        return
    return get_user(uid)

a = create_user('wozozo', 'xxxxxxxx')
b = get_user(a['uid'])
assert a == b
put_user(a['uid'], b['name'], 'yyyyyyyy')

c = get_user_by_auth('yyyyyyyy')

2013-01-01

Elasticity


あけまして、おめでとうございます。巳年なので Pythonista としてはテンションあがりますね。実は、別にそんなことないですけどね。

昨年(2012年)は、継続的デリバリを使っていきました。おかげで、手作業でのテストやデプロイから開放され、作ったものの品質が上がり、かつ、開発のスループットが向上しました。

プロダクト自身ではなく、プロダクトの作り方を考えるのは、想像以上にチャレンジが多く、また、楽しいものでした。

今年は、昨年よりも意図的にテーマを決めてみようかと思いました。

Elasticity について理解を深める

必要に応じて、システムのキャパシティを上げ下げする仕事が増えてきました。これまでは、自分の少ない経験と、識者のアドバイスでなんとかやってきました。今年はこのあたりの技術、知識、経済性などを改めて理解し直します。

Elasticな何かを作ってみる


アプリケーションなのか、ライブラリなのか、デモなの決めていませんが、elastic な何かを作ります。

理由は2つあって、まず、自分のGithub が寂しい限りであること。何もできないようにしか見えないので、何か作ってみたい。

もうひとつは、効率が悪いのですが、自分が作って初めて理解するタイプだからです。読んだだけだと、なんとなく分かった気になるだけで、理解が浅いのですね。学校で習った核反応による中性子の増減の微分方程式なんかも、その計算をするコードを作ろうとして初めて、本当に理解が深まったのでした。字面だけ追っかけてしまうのでしょう。

pyfes 以外でプレゼンする


こちらは効果がよく分からないのですが、教えるときがもっとも学ぶ、という噂がまことしやかに語られます。ですので、やってみようかと。Pyfes では、だらだらしたいので、LTでもいいからどこか別のところでできるといいんぁ、と漠然と考えています。