2.8.0 から使用可能
時間の複雑さ。 すべての呼び出しに対してO(1)。 N は、コレクション内の要素の数です。
要素のコレクションに対してインクリメンタルに反復するために、SCAN コマンドと密接に関連するコマンド SSCAN、HSCAN、および ZSCAN が使用されます。
- SCAN は現在選択されている Redis データベース内のキーのセットを反復します。
- SSCAN は Sets タイプの要素を反復します。
- HSCAN は Hash タイプのフィールドとその関連値を反復します。
これらのコマンドは、呼び出しごとに少数の要素のみを返す漸進的な反復を可能にするので、キーまたは要素の大きなコレクションに対して呼び出されると長時間 (数秒でも) サーバーをブロックする可能性のある KEYS や SMEMBERS のようなコマンドの欠点なしに実運用で使用できます。
しかし、SMEMBERS のようなブロックするコマンドは、与えられた瞬間にセットの一部であるすべての要素を提供できますが、SCAN コマンドのファミリーは、増分的に反復するコレクションが反復プロセス中に変更できるため、返された要素について限られた保証しか提供しません。 ただし、明らかな違いは、SSCAN、HSCAN、および ZSCAN の場合、最初の引数が、Set、Hash、または Sorted Set の値を保持するキーの名前であることです。 SCAN コマンドは、現在のデータベース内のキーを反復するので、キー名の引数を必要としません。したがって、反復されるオブジェクトはデータベースそのものです。
反復処理は、カーソルが 0 に設定されたときに開始し、サーバーから返されたカーソルが 0 になったときに終了します。
redis 127.0.0.1:6379> scan 0 1) "17" 2) 1) "key:12" 2) "key:8" 3) "key:4" 4) "key:14" 5) "key:16" 6) "key:17" 7) "key:15" 8) "key:10" 9) "key:3" 10) "key:7" 11) "key:1" redis 127.0.0.1:6379> scan 17 1) "0" 2) 1) "key:5" 2) "key:18" 3) "key:0" 4) "key:2" 5) "key:19" 6) "key:13" 7) "key:6" 8) "key:9" 9) "key:11"
上記の例では、最初の呼び出しはカーソルとして 0 を使用して、反復処理を開始します。
最初の値は次の呼び出しで使用する新しいカーソル、2 番目の値は要素の配列です。
2番目の呼び出しで返されたカーソルは 0 なので、サーバーは呼び出し元に反復が終了し、コレクションが完全に調査されたことを通知します。
*Scan の保証
SCAN コマンド、および SCAN ファミリーの他のコマンドは、完全な反復に関連する一連の保証をユーザーに提供できます。
- A full iteration always retrieves all the elements that were present in the collection from the start to the end of a full iteration. これは、反復が開始されたときに所定の要素がコレクション内にあり、反復が終了したときにまだそこにある場合、SCAN はある時点でそれをユーザーに返したことを意味します。
- The full iteration never returns any element that was not present in the collection from the start to the end of a full iteration.
しかし、SCAN には関連する状態がほとんどない (カーソルだけ) ため、次のような欠点があります:
- 与えられた要素が複数回返されることがあります。 たとえば、複数回再適用しても安全な操作を実行するために、返された要素のみを使用します。
- 完全な反復の間にコレクションに常に存在しなかった要素は、返されるかどうかは未定です。 コマンドはゼロの要素を返すことも許可されており、クライアントは、返されたカーソルがゼロでない限り、反復が完了したと見なすべきではない。
ただし、返される要素の数は妥当で、つまり、実用上、SCAN は、大きなコレクションの反復時に数十の要素の順序で最大数を返すか、反復コレクションがコード化データ構造として内部的に表されるほど小さい場合に、1回の呼び出しでコレクションのすべての要素を返せる場合があります (小さなセット、ハッシュおよびソートのセットでこれが発生します)。
しかし、COUNT オプションを使用して、ユーザーが呼び出しごとに返される要素の数の大きさを調整する方法があります。
*COUNT オプション
反復ごとに返される要素の数について SCAN が保証を提供しない一方、COUNT オプションを使用して SCAN の動作を経験的に調整することが可能になります。 基本的に COUNT を使用して、ユーザーはコレクションから要素を取得するために、すべての呼び出しで実行されるべき作業量を指定します。
- デフォルトの COUNT 値は 10 です。
- キー スペースを反復する場合、またはハッシュ テーブルで表現できるほど大きな Set、Hash、Sorted Set の場合、MATCH オプションが使用されていないと仮定すると、サーバーは通常 1 回の呼び出しごとに count または count より少し多い数の要素を返します。
- intsets (整数値のみからなる小さなセット) としてエンコードされたセット、または ziplist (小さなハッシュや小さな個々の値からなるセット) としてエンコードされたハッシュおよびソート セットを反復する場合、COUNT 値に関係なく通常最初の SCAN コールですべての要素が返されます。 次の呼び出しで渡されるカーソルがコマンドの前の呼び出しで得られたものである限り、呼び出し側は必要に応じて 1 つの反復から他の反復へとカウントを自由に変更できます。
*MATCH オプション
唯一の引数としてパターンを取る KEYS コマンドの動作と同様に、与えられたグロブ スタイルのパターンに一致する要素のみを反復することが可能です。
これを行うには、SCAN コマンドの最後に
MATCH <pattern>
引数を追加します (すべての SCAN 系コマンドで機能します)。これは、MATCH による反復処理の例です
redis 127.0.0.1:6379> sadd myset 1 2 3 foo foobar feelsgood (integer) 6 redis 127.0.0.1:6379> sscan myset 0 match f* 1) "0" 2) 1) "foo" 2) "feelsgood" 3) "foobar" redis 127.0.0.1:6379>
要素がコレクションから取得された後で、クライアントへデータを返す前に MATCH フィルターが適用されるということが重要なポイントになります。 これは、パターンがコレクション内のほとんど要素にマッチしない場合、SCAN はほとんどの反復で要素を返さない可能性があることを意味します。
redis 127.0.0.1:6379> scan 0 MATCH *11* 1) "288" 2) 1) "key:911" redis 127.0.0.1:6379> scan 288 MATCH *11* 1) "224" 2) (empty list or set) redis 127.0.0.1:6379> scan 224 MATCH *11* 1) "80" 2) (empty list or set) redis 127.0.0.1:6379> scan 80 MATCH *11* 1) "176" 2) (empty list or set) redis 127.0.0.1:6379> scan 176 MATCH *11* COUNT 1000 1) "0" 2) 1) "key:611" 2) "key:711" 3) "key:118" 4) "key:117" 5) "key:311" 6) "key:112" 7) "key:111" 8) "key:110" 9) "key:113" 10) "key:211" 11) "key:411" 12) "key:115" 13) "key:116" 14) "key:114" 15) "key:119" 16) "key:811" 17) "key:511" 18) "key:11" redis 127.0.0.1:6379>
ほとんどの呼び出しはゼロ要素を返しますが、最後の呼び出しでは COUNT 1000 が使用されており、その繰り返しでさらにスキャンするようコマンドに強制されます。
*TYPE オプション
バージョン 6.0 では、このオプションを使用して、与えられた
type
に一致するオブジェクトのみを返すよう SCAN に要求することができ、特定のタイプのキーを探してデータベースを繰り返し処理することが可能になります。引数の
type
は、TYPE コマンドが返すのと同じ文字列名です。 GeoHash、HyperLogLogs、Bitmaps、Bitfields などの一部の Redis タイプは、内部的に string や zset などの他の Redis タイプを使って実装されている場合があり、SCAN によって同じタイプの他のキーと区別できない癖があることに注意してください。 たとえば、ZSET と GEOHASH です。redis 127.0.0.1:6379> GEOADD geokey 0 0 value (integer) 1 redis 127.0.0.1:6379> ZADD zkey 1000 value (integer) 1 redis 127.0.0.1:6379> TYPE geokey zset redis 127.0.0.1:6379> TYPE zkey zset redis 127.0.0.1:6379> SCAN 0 TYPE zset 1) "0" 2) 1) "geokey" 2) "zkey"
注意すべきは、TYPE フィルターはデータベースから要素が取得された後にも適用されるので、このオプションによって、サーバーが反復を完全に完了するために行う作業量が減るわけではなく、まれなタイプの場合は多くの反復で要素を受け取らないかもしれないことです。
*Multiple parallel iterations
イテレーターの完全な状態がカーソル内にあり、呼び出しごとに取得されてクライアントに返されるので、無限のクライアントが同じコレクションを同時に反復することが可能です。
*反復処理の途中終了
サーバー側には状態がなく、完全な状態がカーソルによってキャプチャされるため、呼び出し側はサーバーに何らかの方法で合図することなく、自由に反復処理を途中で終了できます。
*Calling SCAN with a corrupted cursor
壊れた、負の、範囲外の、またはその他の無効なカーソルで SCAN を呼び出すと、未定義の動作になりますが、決してクラッシュは起こりません。
使用できる唯一の有効なカーソルは次のとおりです:
- 反復を開始するときのカーソル値は 0 です。
*終了の保証
反復されるコレクションのサイズが与えられた最大サイズに制限されたままである場合のみ、SCAN アルゴリズムは終了することが保証されます。
これは直感的に理解しやすいと思います。コレクションが大きくなると、すべての可能な要素を訪問するために行う作業が増え、反復を終了する能力は、SCAN への呼び出し回数とその COUNT オプション値に依存し、コレクションの成長速度に比例します。
*なぜ SCAN は 1 回の呼び出しで集約データ型のすべてのアイテムを返すのか
オプションのドキュメントでは、このコマンドのファミリーは、
COUNT
オプション値にかかわらず、一度の呼び出しで Set、Hash または Sorted Set のすべての要素を返すことがあると説明しています。 なぜこのようなことが起こるかというと、カーソルベースのイテレータは、スキャンする集約データ型がハッシュテーブルとして表現される場合にのみ実装可能であり、有用であるためです。 しかし、Redisは、小さな集約データ型が、与えられたアイテム量または単一要素の与えられた最大サイズに達するまで、コンパクトな単一割り当てパックエンコーディングを使用して表されるメモリ最適化を使用しています。しかし、いったんデータ構造が大きくなり、本当のハッシュ テーブルを使用するようになると、SCAN コマンドのファミリーは通常の動作に戻ることになります。 すべての要素を返すというこの特別な動作は、小さな集合体に対してのみ当てはまるので、コマンドの複雑さや待ち時間に影響を与えないことに注意してください。 したがって、1 回の呼び出しで返される要素の最大数は、集約データ型がどの程度の大きさで、まだパックされた表現を使用できるかに依存します。 SCAN itself never shows this behavior because the key space is always represented by hash tables.
*Return value
SCAN, SSCAN, HSCAN and ZSCAN return a two elements multi-bulk reply, where the first element is a string representing an unsigned 64 bit number (the cursor), and the second element is a multi-bulk with an array of elements.
- SCAN array of elements is a list of keys.
- SSCAN array of elements is a list of Set members.
- HSCAN array of elements contain two elements, a field and a value, for every returned element of the Hash.
- ZSCAN array of elements contain two elements, a member and its associated score, for every returned element of the sorted set.
*History
-
>= 6.0
: Supports the TYPE subcommand.
*Additional examples
Iteration of a Hash value.
redis 127.0.0.1:6379> hmset hash name Jack age 33 OK redis 127.0.0.1:6379> hscan hash 0 1) "0" 2) 1) "name" 2) "Jack" 3) "age" 4) "33"