Previous topic

接続処理

Next topic

制御コマンド

This Page

全データ型対応の操作

EXISTS(key)

計算時間: O(1)

指定されたキー key が存在するか確認します。存在する場合は”1”が返ります。存在しない場合は”0”が返ります。キーに対応する値が空文字列でも”1”が返ることに注意してください。

返り値

Integer reply(整数値)。具体的には下記:

1 if the key exists.
0 if the key does not exist.
DEL(key1, key2, ..., keyN)

計算時間: O(1)

指定された複数のキー keyN を削除します。キーが存在しない場合は何の操作も行われません。返り値は削除されたキーの数となります。

返り値

Integer reply(整数値)。具体的には下記:

an integer greater than 0 if one or more keys were removed
0 if none of the specified key existed
TYPE(key)

計算時間: O(1)

キー key で格納されている値の型を文字列型で返します。型は “none”, “string”, “list”, “set”のいずれかです。 “none”はキーが存在しない場合に返ります。

Note

“sortedset”はないのか?要確認。

返り値

Status code reply(ステータスコード)。具体的には下記:

"none" if the key does not exist
"string" if the key contains a String value
"list" if the key contains a List value
"set" if the key contains a Set value
"zset" if the key contains a Sorted Set value
"hash" if the key contains a Hash value

参照

Redisデータ型

Note

あとで各データ型へのリンクを貼る

KEYS(pattern)

計算時間: O(N) (nはデータベース内のキーの数。キーとパターンの数は制限されていると想定している。)

glob形式のパターン pattern にマッチするすべてのキーを空白区切りの文字列で返します。例えばデータベース内に”foo”と”foobar”というキーがある場合は KEYS foo* というコマンドで”foo foobar”という文字列が返ります。

この操作は計算時間O(n)となっているが、定数時間は非常に小さいものとなっています。たとえばRedisはエントリーモデルのノートPCで100万キーを持つデータベースを40ミリ秒で読み込みます。もちろんこのコマンドは注意深く使わないとデータベース性能を落としてしまうということを意識するにこしたことはありません。

言い換えると、このコマンドはデバッグやデータベースのスキーマの変更を行うなどの特別な操作を除いて使うべきではありません。通常のコードでは使わないでください。オブジェクトのサブセットをくっつけたい場合はRedisセット型を使ってください。

glob形式のパターンの例です:

h?llo will match hello hallo hhllo
h*llo will match hllo heeeello
h[ae]llo will match hello and hallo, but not hillo
Use \ to escape special chars if you want to match them verbatim.

返り値

Multi bulk replyが返る
RANDOMKEY()

計算時間: O(1)

現在選択してされているデータベースからランダムでキーをひとつ選択して返します。

返り値

Single line reply(単一行)が返ります。具体的にはランダムに選択されたキーまたはデータベースが空のときは空文字列が返ります。
RENAME(oldkey, newkey)

計算時間: O(1)

自動的にキー oldkeynewkey にリネームします。もし古いキーと新しいキーの名前が一緒だった場合はエラーが返ります。 newkey が存在する場合は上書きされます。

返り値

Status code reply(ステータスコード)が返ります。
RENAMENX(oldkey, newkey)

計算時間: O(1)

返り値

Integer reply(整数値)が返ります。具体的には下記:

1 if the key was renamed
0 if the target key already exist
DBSIZE()

現在選択されているデータベースのキーの数を返します。

返り値

Integer reply(整数値)
EXPIRE(key, seconds)
EXPIREAT(key, unixtime)
..(versionadded::, 1.1)
PERSIST(key)

計算時間: O(1)

指定したキー key のタイムアウト時間 seconds を設定する。タイムアウト時間が過ぎたらキーはサーバによって自動的に削除されます。タイムアウト時間が設定されたキーはRedis用語では”volatile”(揮発性がある)と呼ばれます。

揮発性のキーは他のキーのようにディスクに書き込まれます。タイムアウト時間は他のデータセットの性質と同様に永続的なものです。揮発性のキーを持っているデータセットを保存してからサーバを停止しても、Redis内の時間経過は止まりません。Redisはディスクに保存する際にそのキーがいつ無効になるかを残り時間ではなくUNIX時間で記録しているのでこれが実現できるのです。

EXPIREATEXPIRE と同様に動作しますが、 TTL で取得できるような残り秒数ではなく、UNIX時間の形で絶対時刻を有効期限を指定します。

EXPIREAT はAppend Only File(追記専用ファイル)の永続モードの実装のために作成されました。これによって、追記専用ファイルの場合は EXPIRE コマンドは自動的に EXPIREAT コマンドに変換されます。もちろん EXPIREAT はプログラマが単純に指定したキーを将来指定しあ時刻に無効にさせる、というような用途で使うことができます。

Redis 2.1.3からすでにタイムアウト時間を設定したキーに対して、タイムアウト時間を更新することが出来るようになりました。またタイムアウト時間を設定したキー全てに対して、 PERSIST コマンドを使ってタイムアウトを無効にすることも出来るようになりました。

どのようにキーからタイムアウトが削除されるか

SET を使ってキーに新しい値が紐付けれたとき、あるいはキーが DEL コマンドで削除されたときにタイムアウトが削除されます。

揮発性のキーに対する書き込み制限

Warning

Redis 2.1.3以上では揮発性のキーに対する書き込み制限は一切ありません。しかし現在の安定版2.0.0を含むそれ以前のバージョンでは次のような制限があります。

揮発性のキーに対応する値に対して修正を行うような LPUSH, LSET などの操作に対しては特別なセマンティクスがあります。基本的に揮発性のキーは書き込みの対象となった場合は破壊されます。以下の例を見て下さい:

% ./redis-cli lpush mylist foobar /Users/antirez/hack/redis
OK
% ./redis-cli lpush mylist hello  /Users/antirez/hack/redis
OK
% ./redis-cli expire mylist 10000 /Users/antirez/hack/redis
1
% ./redis-cli lpush mylist newelement
OK
% ./redis-cli lrange mylist 0 -1  /Users/antirez/hack/redis
1. newelement
TTL(key)

TTL コマンドは EXPIRE が設定されたキー key の存命時間を秒で返す。このコマンドで確認できることによって、Redisクライアントが与えられたキーがあとどれくらいデータセットの一部であるか確認することができます。もしキーが存在しない、あるいは EXPIRE が設定されていない場合は”-1”が返ります。

返り値

Integer reply(整数値)が返ります
SELECT(index)

ゼロから始まる数値 index インデックス付けされたデータベースを選択します。デフォルトの設定では新しいクライアント自動的にDB 0に接続されます。

返り値

Status code reply(ステータスコード)が返ります。
MOVE(key, dbindex)

指定したキー key を現在選択されているデータベースから指定したインデックス index のデータベースに移します。無事移動できた場合のみ”1”を返し、対象のキーがすでに指定したデータベースに存在する、または対象のキーが見つからない場合は”0”を返します。この性質から MOVE をロックのために使うこともできます。

返り値

Integer reply(整数値)が返ります。具体的には下記:

1 if the key was moved
0 if the key was not moved because already present on the target DB or was not found in the current DB.
FLUSHDB()

現在選択されているデータベースからすべてのキーを削除します。このコマンドは決して失敗しません。

返り値

Status code reply(ステータスコード)が返ります。
FLUSHALL()

現在選択されているものだけでなく、存在するすべてのデータベースからすべてのキーを削除します。このコマンドは決して失敗しません。

返り値

Status code reply(ステータスコード)が返ります。
WATCH(key1, key2, ..., keyN)

New in version 2.1.0.

UNWATCH()
MULTI()
COMMAND_1(...)
COMMAND_2(...)
COMMAND_N(...)
EXEC()
DISCARD()

MULTI, EXEC, DISCARD, WATCH コマンドはRedisトランザクションの基礎です。Redisトランザクションでは単一ステップでひとまとめのRedisコマンドを実行出来るようにしてあります。このトランザクションでは2つのことが保証されています:

トランザクション中のすべてのコマンドはシリアライズ化され、順番に実行されます。他のクライアントからのリクエストがRedisトランザクションの実行中に行われることは決してありません。このことによって一連のコマンドは単一のアトミックな操作として扱われることが保証されます。

すべてのコマンドが実行されるか全く実行されないかのどちらかとなります。 EXEC コマンドはトランザクション中のすべてのコマンドの実行のトリガーとなります。なので、もしクライアントが MULTI を呼び出す前にサーバへの接続を失った場合は、操作はひとつも実行されませんが、 EXEC を呼べばすべての操作が実行されます。このルールの例外としてAppend Only File(追記専用ファイル、以下AOF)が有効になっている場合があります。この場合、Redisトランザクションに関するコマンドは操作が完了するまではAOFにログを録ります。したがってもしRedisサーバがクラッシュする、もしくはシステムアドミニストレータによってkillされたとき、トランザクションの操作の中から部分的に実行された分が登録される、ということが起きえます。

Redis 2.1.0から、上記の2項目に加えてさらにCAS(check and set)操作に似た方法でキーの束を楽観的ロックすることが可能になりました。これについては本文のあとの方で説明します。

使い方

Redisのトランザクションは MULTI コマンドを使って登録します。コマンドはつねにOKを返します。このときユーザは複数のコマンドを発行できます。これらのコマンドを実行する代わりに、Redisではキューにためます。キュー内のコマンドは EXEC が呼ばれたタイミングで実行されます。

DISCARD を呼ぶとトランザクションキューをフラッシュして、トランザクションから出ます。

Rubyクライアントのでの例です:

?> r.multi
=> "OK"
>> r.incr "foo"
=> "QUEUED"
>> r.incr "bar"
=> "QUEUED"
>> r.incr "bar"
=> "QUEUED"
>> r.exec
=> [1, 1, 2]

この例でわかるように、 MULTI はトランザクション中の各コマンドの返り値を要素に持った配列を返します。要素の並び順はコマンドの並び順に一致します。

Redisへ接続している間に MULTI が呼びだされたとき、すべてのコマンドが文法上も引数も正しく呼びだされたときは文字列 “QUEUED” を返します。実行時にうまく動作しなくてもかまいません。

プロトコルレベルではより明確に見て取れます。次の例は文法上正しいですが実行時にコマンドが失敗する例です:

Trying 127.0.0.1...
Connected to localhost.
Escape character is '^]'.
MULTI
+OK
SET a 3
abc
+QUEUED
LPOP a
+QUEUED
EXEC
*2
+OK
-ERR Operation against a key holding the wrong kind of value

MULTI は要素が2つのBulk replyを返してきました。そのうち一つは”+OK”でもう一つは”-ERR”です。ユーザにエラーを提供する方法はクライアントライブラリ次第です。

Warning

コマンドがエラーをあげたときですら、キューに入っているそれ以外のコマンドは処理されます。Redisはエラーが得られたとしてもプロセスを 止めません 。 他の例では再度telnetを用いて書き込みプロトコルを使っていますが、文法エラーができるだけ早く報告されるように設定しています:

MULTI +OK INCR a b c -ERR wrong number of arguments for ‘incr’ command

この場合は、文法エラーによって”bad”な INCR コマンドはキューに入りませんでした。

DISCARDコマンド

DISCARD はトランザクションを中止するために用いられます。それ以降のコマンドは実行されません。そしてクライアントの状態がトランザクション外では再度通常となります。Rubyクライアントの例を挙げます:

?> r.set("foo",1)
=> true
>> r.multi
=> "OK"
>> r.incr("foo")
=> "QUEUED"
>> r.discard
=> "OK"
>> r.get("foo")
=> "1"

確認とWATCHを用いたセット(CAS)トランザクション

WATCH はRedisトランザクションにCAS (Check and Set)ビヘイビアを提供するために用います。

WATCH されたキーは変更を検知するために監視されています。もし EXEC を呼ぶ前にこれらのキーが修正された場合、すべてのトランザクションは中止され、 EXEC はトランザクションが失敗したことを通知するためにnilオブジェクトを返します。(Null Multi Bulk replyが返ります)

たとえばキーを自動的に1増やさないといけないという状況を考えてみましょう。( INCR コマンドがあることは承知ですが、いまは忘れておきましょう)

まずはこんな例を考えてみましょう:

val = GET mykey
val = val + 1
SET mykey $val

このサンプルは1つのクライアントが限られた時間で動作する場合であれば上手く動くと思います。もし複数のクライアントが同時にキーをインクリメントしようとしたら、競合状態に陥ります。例えば、クライアントAとクライアントBが古い値、ここでは10としますが、を読んだとします。この値は両方のクライアントによってインクリメントされ11となります。そして最終的にそのキーの値として12ではなく11がセットされてしまうのです。

WATCH コマンドのおかげでこの問題をうまく解決できます:

WATCH mykey
val = GET mykey
val = val + 1
MULTI
SET mykey $val
EXEC

上記のコードを使うことで、もし競合状態になって他のクライアントが WATCHEXEC の間に val の値を修正した場合はトランザクションは失敗します。

この場合出来ることは、再度操作を実行して今度は競合状態にならないことを願うだけです。このような形式でのロックは楽観的ロックと呼ばれ、複数のクライアントが非常に多くのキーにアクセスするような多くの問題で非常に有力なロック形式となっています。衝突が起きる、ということはあまりありません。なので普通は操作を何度もやり直すということはありません。

WATCH explained

では WATCH は実際には何をするものなのでしょうか。それは EXEC に条件をつけるコマンドと理解してください。Redisにもし他のクライアントが WATCH したキーを修正しなかった場合のみトランザクション処理を行うという条件をつけるのです。もし修正されてしまった場合はトランザクションは実行されません。( WATCH で揮発性のキーを監視して、Redisが監視開始後にそのキーを無効とした場合、 EXEC は動作することに注意してください)

WATCH は複数回呼ぶことが出来ます。すべての WATCH の呼出しにおいて、それぞれの呼び出し時から EXEC の呼び出し時まで監視は有効になっています。

EXEC が呼び出されたとき、成功したかどうかにかかわらず、すべてのキーは UNWATCH の状態になります。クライアントの接続が閉じた時も同様です。

すべての監視下のキーをフラッシュするために UNWATCH コマンドを使うこともできます(引数はありません)。たとえばいくつかのキーを楽観的ロックしたあとに、それらのキーを変更したいという理由でトランザクションをしたい時があります。しかしキーに対応する現在の値を読んだあとにはもう処理を行ないたくない、というときに UNWATCH を使います。これでコネクションは新しいトランザクションの為に使えます。

Note

このパラグラフ翻訳があやしい

WATCH used to implement ZPOP

WATCH コマンドを使ってアトミックな操作を作成する良い例を次に示します。それを見ることで、 WATCH が無かったら ZPOP が実装できなかったとわかるでしょう。 ZPOP はソート済みセットの低いスコアの方から要素をアトミックにポップするコマンドです。これは最も単純な実装例です:

WATCH zset
ele = ZRANGE zset 0 0
MULTI
ZREM zset ele
EXEC

もし EXEC が失敗したら(nil値を返したら)、単純に操作を再実行するだけです。

戻り値

Multi bulk replyを返します。具体的には下記:

The result of a MULTI/EXEC command is a multi bulk reply where every element is the return value of every command in the atomic transaction.

もし MULTI/EXEC トランザクションが WATCH がキーが修正されたのを検知したせいで中止になった場合、Null Multi Bulk replyが返ります。

SORT(key, [BY, pattern], [LIMIT, start, count], [GET, pattern], [ASC|DESC], [ALPHA], [STORE, dstkey])

リスト、セット、ソート済みセット内の要素をキーに対応する値でソートします。デフォルトではソートは倍精度浮動小数の値で比較されます。次はは最も単純な形のソートです。

SORT mylist

mylist は数字のリストを保持しています。返り値は昇順に並び替えられたリストとなります。もし降順にしたい場合は DESC を使います。

SORT mylist DESC

ASC も使えますが、デフォルトで指定されているので使う必要はありません。もし辞書順で並び替えたいときは ALPHA を使います。 RedisはUTF-8を前提にしているので、他の文字コードを使う場合は正しく LC_COLLATE を設定してください。

LIMIT オプションを使うことで返す要素数を制限することも出来ます。

SORT mylist LIMIT 0 10

上の例では SORT は最初の要素(0番目)から始めて10要素を返します。ほぼすべてのソートのオプションは一緒に使えます。たとえばこんな感じです。

SORT mylist LIMIT 0 10 ALPHA DESC

この例では mylist は辞書順で降順にソートされ、最初の10要素を返します。

時にリスト、セット、ソート済みセット内の要素を直接比較するのではなく、外部キーを重みとしてソートしたい時があります。たとえばリスト mylist が要素 1,2,3,4 を持っていて、object_1, object_2, object_3, object_4 に保存されているオブジェクトのユニークIDになっています。一方でweight_1, weight_2, weight_3, weight_4は重みを保存していて、その重みを使ってIDをソートしたいとします。この場合は次のコマンドを使います。

外部キーでソートする

SORT mylist BY weight_*

BY オプションは重みを保存しているキー名を生成するためにパターンを受け付けることができます(今回はweight_*です)重みのキー名は最初に現れるアスタリスクをリスト内の実際に値に置き換えることで得られます。(この例では1,2,3,4です)

前の例ではソートされたIDを返すだけでした。よく実際のオブジェクト(たとえばobject_1, ..., object4)をソートする必要があります。この場合は次のコマンドで出来ます。

SORT mylist BY weight_* GET object_*

外部キーを取得する

元々のリスト、セット、ソート済みセットからさらにキーを取得するために GET オプションを複数回使うことが出来ます。

Redis 1.1からリスト要素自身を # を使うことで取得できるようになりました。

SORT mylist BY weight_* GET object_* GET #

SORTの結果を保存する

デフォルトでは SORT は返り値としてソートされた要素を返します。 STORE オプションを使うことで要素を返す代わりに、 SORT はこの要素をRedisリスト型として指定したキーの保存します。このような形です:

SORT mylist BY weight_* STORE resultkey

SORT ... STORE を用いた興味深いパターンとして、 EXPIRE のタイムアウトを結果のキーに関連付けて使う方法があります。こうすることでしばらくの間ソートの結果がキャッシュされたアプリケーション内でクライアントはリクエストごとに SORT を発行する代わりにキャッシュされたリストを参照することができます。キーがタイムアウトした場合は再度 SORT ... STORE を用いることで更新されたソート結果を使うことが出来ます。

このパターンを実装するときには複数のクライアントがソート結果のキャッシュを同時に作成しないように気をつけなければいけません。したがって何らかのロックを使わなければいけないでしょう。(たとえば SETNX を使うなど)

全くソートしない

BY オプションは “nosort” 識別子を取ることもできます。これは外部キーを取得したいけれど、ソートのオーバーヘッドは避けたい時に便利です。

ソートとハッシュ:ハッシュフィールドによるBYとGET

BYGET オプションをハッシュフィールドに対して使うことも可能です。以下はその例です:

SORT mylist BY weight_*->fieldname
SORT mylist GET object_*->fieldname

2文字の文字列 -> はハッシュフィールドを指し示すのに使います。キーが BYGET によって前述のとおりに通常のキーに置き換えられて、特定のフィールドを取得するためにキーが指定されているハッシュがアクセスされます。

Note

いい翻訳が難しい

返り値

Multi bulk replyが返ります。具体的にはソートされたリストです。