RedisのSorted Setで時系列のデータを扱う

redisでtwitterのタイムラインのように時系列でデータを保存することを考えてみる。

新しく追加されたデータを先に取得できるようにする必要がある。

ページングするのに、最後に返したデータのポジションは取得できず、データそのものが渡されると仮定。

つまりデータからindexが取得可能である必要がある。

listを使うと頭から走査しないと取得できないので、sorted mapでscoreにシステム時刻を入れることを試してみる。

pythonで操作した。

まず順番に5つのデータを入れてみる

# coding=utf-8

import redis
import time

client = redis.Redis()

KEY = "loglog"
VALUES = ["one", "two", "three", "four", "five"]
# 初期化
client.delete(KEY)


def get_score():
    """ 現在時刻をscoreとして取得する関数
    """
    return int(time.time() * 1000)

# 順番に値を追加
for value in VALUES:
    client.zadd(KEY, value, get_score())
    time.sleep(0.1)


この時点でzrangeで全件取得するとscoreの昇順、すなわち古い順で返される

print client.zrange(KEY, 0, -1)
# ['one', 'two', 'three', 'four', 'five']


zrevrangeで逆順に取得、新しいものを先に取得できる

print client.zrevrange(KEY, 0, -1)
# ['five', 'four', 'three', 'two', 'one']


値を入れなおすと順序が変わる

# 値の更新
client.zadd(KEY, "four", get_score())

# 更新された値が先頭になる
print client.zrevrange(KEY, 0, -1)
# ['four', 'five', 'three', 'two', 'one']

値からindexを取得してみる。
zrankで値の順位が取得できるが、zrevrankを使えば逆順で取得できる。

idx = client.zrevrank(KEY, "three")
# ['four', 'five', 'three', 'two', 'one']なので2が返される


indexからn件取得する処理を考えてみる

# idxの値は含まないので+1
start = idx + 1
n = 2
print client.zrevrange(KEY, start, start + n)
# ['two', 'one']

最後にmax件数を決めておいて、超過したら古いを削除する処理を考えてみる
zremrangebyrankが用意されてるがこれを逆順で使うために、maxをマイナスで指定する

# max3件と仮定
_max = 3
client.zremrangebyrank(KEY, 0, -(_max + 1))
print client.zrevrange(KEY, 0, -1)
# 古い2件が削除され、全部で3件になった
# ['four', 'five', 'three']