Amazon DynamoDB
開発者ガイド (API バージョン 2012-08-10)

スキャンの使用

Scan オペレーションは、テーブルまたは セカンダリインデックス のすべての項目を読み込みます。デフォルトでは、Scan オペレーションはテーブルまたはインデックスのすべての項目のデータ属性を返します。ProjectionExpression パラメータを使用し、Scan がすべての属性ではなく一部のみを返すようにできます。

Scan は常に結果セットを返します。一致する項目がない場合、結果セットは空になります。

1 回の Scan リクエストで、最大 1 MB のデータを取得できます。DynamoDB では、必要に応じてこのデータにフィルタ式を適用して、結果をユーザーに返す前に絞り込むことができます。

Scan のフィルタ式

Scan 結果の絞り込みが必要な場合は、オプションでフィルタ式を指定できます。フィルタ式によって、Scan 結果の返される項目が決まります。他のすべての結果は破棄されます。

フィルタ式は、Scan の完了後、結果が返される前に適用されます。そのため、Scan は、フィルタ式があるかどうかにかかわらず、同じ量の読み込みキャパシティーを消費します。

1 回の Scan オペレーションで、最大 1 MB のデータを取得できます。この制限は、フィルタ式を評価する前に適用されます。

Scan では、パーティションキー属性とソートキー属性を含む任意の属性をフィルタ式で指定できます。

フィルタ式の構文は、条件式の構文と同じです。フィルタ式は、条件式と同じコンパレータ、関数および論理演算子を使用できます。詳細については, 条件式.

次の AWS CLI の例では Thread テーブルをスキャンして、特定のユーザーによって最後に投稿された項目のみを返します。

aws dynamodb scan \ --table-name Thread \ --filter-expression "LastPostedBy = :name" \ --expression-attribute-values '{":name":{"S":"User A"}}'

結果セットの項目数の制限

Scan オペレーションは、結果で返される項目数を制限することができます。これを行うには、Limit パラメータに項目の最大数を設定します。

たとえば、フィルタ式を使用せず、Limit 値を 6 として、テーブルを Scan するとします。Scan 結果には、リクエストからのキー条件式に一致するテーブルからの最初 6 つの項目が含まれます。

ここで、Scan にフィルタ式を追加するとします。この場合、DynamoDB は返される 6 つの項目にフィルタ式を適用し、一致しない項目を廃棄します。最終的な Scan 結果はフィルタリングされる項目の数に応じて、6 つ以下の項目を含みます。

ページ単位の出力件数を指定

DynamoDB では、Scan オペレーションで得られた結果のページ分割を行うことができます。ページ分割を行うことで Scan 結果が 1 MB サイズ (以下) のデータの「ページ」に分割されます。アプリケーションは結果の最初のページ、次に 2 ページと処理できます。

1 つの Scan は、1 MB のサイズ制限の範囲内の結果セットだけを返します。さらに結果があるかどうかを確認して、一度に 1 ページずつ結果を取り出すには、アプリケーションで次の操作を行う必要があります。

  1. 低レベルの Scan 結果を確認します。

    • 結果に LastEvaluatedKey 要素が含まれる場合、ステップ 2 に進みます。

    • 結果に LastEvaluatedKeyない場合、これ以上取得する項目はありません。

  2. 以前のものと同じパラメータを使用して新しい Scan リクエストを作成します。今回は、ステップ 1 からの LastEvaluatedKey 値を取得して、新しい Scan リクエストの ExclusiveStartKey パラメータとして使用します。

  3. 新しい Scan リクエストを実行します。

  4. ステップ 1 に進んでください。

言い換えると、Scan レスポンスからの LastEvaluatedKey を、次の Scan リクエストの ExclusiveStartKey として使用する必要があります。Scan レスポンスに LastEvaluatedKey 要素がない場合、結果の最後のページを取得します。(結果セットの最後まで到達したことを確認できるのは、LastEvaluatedKey がないときだけです)

AWS CLI を使用してこの動作を表示できます。CLI は低レベル Scan リクエストを DynamoDB に送信し、LastEvaluatedKey が結果に表示されなくなるまで送信を繰り返します。次の AWS CLI の例を見てください。この例は、Movies テーブル全体をスキャンしますが、特定のジャンルの映画のみを返します。

aws dynamodb scan \ --table-name Movies \ --projection-expression "title" \ --filter-expression 'contains(info.genres,:gen)' \ --expression-attribute-values '{":gen":{"S":"Sci-Fi"}}' \ --page-size 100 \ --debug

通常、AWS CLI はページ分割を自動的に処理します。ただし、この例では、CLI の --page-size パラメータによってページあたりの項目数が制限されています。--debug パラメータは、リクエストとレスポンスについての低レベルの情報を表示します。

この例を実行した場合、DynamoDB からの最初のレスポンスは次のようになります。

2017-07-07 12:19:14,389 - MainThread - botocore.parsers - DEBUG - Response body: b'{"Count":7,"Items":[{"title":{"S":"Monster on the Campus"}},{"title":{"S":"+1"}}, {"title":{"S":"100 Degrees Below Zero"}},{"title":{"S":"About Time"}},{"title":{"S":"After Earth"}}, {"title":{"S":"Age of Dinosaurs"}},{"title":{"S":"Cloudy with a Chance of Meatballs 2"}}], "LastEvaluatedKey":{"year":{"N":"2013"},"title":{"S":"Curse of Chucky"}},"ScannedCount":100}'

レスポンスの LastEvaluatedKey は、すべての項目が取得されたわけではないことを示します。これを受けて、AWS CLI は別の Scan リクエストを DynamoDB に送信します。このリクエストとレスポンスのパターンが、最終レスポンスまで繰り返されます。

2017-07-07 12:19:17,830 - MainThread - botocore.parsers - DEBUG - Response body: b'{"Count":1,"Items":[{"title":{"S":"WarGames"}}],"ScannedCount":6}'

LastEvaluatedKey がない場合、これ以上取得する項目がないことを示します。

注記

AWS SDK は低レベルの DynamoDB レスポンス (LastEvaluatedKey の存在または不在を含む) を処理し、ページ分割された Scan 結果のさまざまな抽象化を提供します。たとえば、SDK for Java ドキュメントインターフェイスは java.util.Iterator サポートを提供するため、結果を一度に 1 つずつ確認できます。

各種のプログラミング言語のサンプルコードについては、『Amazon DynamoDB 入門ガイド』と、該当言語の AWS SDK ドキュメントを参照してください。

結果での項目のカウント

Scan レスポンスには、条件に一致する項目に加えて次の要素が含まれます。

  • ScannedCountScanFilter が適用される前に評価される項目数。ScannedCount 値が大きく、Count 結果が小さいまたはない場合は、Scan オペレーションが不十分であることを示しています。リクエストでフィルタを使用していない場合は、ScannedCountCount と同じです。

  • Count - フィルタ式 (存在する場合) が適用された、残っている項目数。

注記

フィルタ式を使用しない場合、ScannedCountCount は同じ値を持ちます。

Scan 結果セットのサイズが 1 MB より大きい場合、ScannedCount および Count は、合計項目数の一部の数のみを表します。すべての結果を取得するためには、複数の Scan オペレーションを実行する必要があります (ページ単位の出力件数を指定 を参照してください)。

Scan レスポンスには、特定の Scan によって処理された項目の ScannedCount および Count が含まれます。すべての Scan リクエストの合計を取得するには、ScannedCount および Count の実行中の集計を維持することができます。

Scan で消費されるキャパシティーユニット

任意のテーブルまたは セカンダリインデックス で Scan できます。Scan オペレーションでは、次のように読み込みキャパシティーユニットを消費します。

...を Scan する場合 DynamoDB は ... からの読み込みキャパシティーユニットを消費します。
テーブルのプロビジョニングされた読み込みキャパシティー。
Global secondary index インデックスのプロビジョニングされた読み込みキャパシティー。
ローカルセカンダリインデックス ベーステーブルのプロビジョニングされた読み込みキャパシティー。

デフォルトでは、Scanオペレーションはどのくらいの読み込みキャパシティーを消費するかについてのデータを返しません。ただし、この情報を取得するために Scan リクエストで ReturnConsumedCapacityパラメータを指定できます。ReturnConsumedCapacity の有効な設定を以下に示します。

  • NONE - 消費されたキャパシティーデータは返されません。(これがデフォルトです)

  • TOTAL - レスポンスには消費された読み込みキャパシティーユニットの合計値が含まれます。

  • INDEXES - レスポンスは、アクセスする各テーブルとインデックスの消費されるキャパシティーとともに、消費される読み込みキャパシティーユニットの合計値を示します。

DynamoDB はアプリケーションに返されるデータ量ではなく、項目のサイズに基づいて、消費される読み込みキャパシティーユニットの数を計算します。このため、消費されるキャパシティーユニットの数は、(射影式を使用して) 属性のすべてをリクエストしても (デフォルトの動作) 一部をリクエストしても、同じになります。数は、フィルタ式を使用していてもいなくても同じです。

Scan の読み込み整合性

Scan オペレーションは、結果的に整合性のある読み込みをデフォルトで行います。つまり、Scan 結果が、最近完了した PutItem または UpdateItem オペレーションによる変更を反映しない場合があります。詳細については、「読み込み整合性」を参照してください。

強力な整合性のある読み込みが必要な場合は、Scan が開始する時に ConsistentRead パラメータを Scan リクエストで true に設定できます。これにより、Scan が開始する前に完了した書き込みオペレーションがすべて Scan 応答に含められます。

ConsistentReadtrue に設定し、DynamoDB ストリーム と同時に使用すると、テーブルのバックアップまたはレプリケーションシナリオで役立ちます。最初に、テーブル内のデータの整合性のあるコピーを取得するため、ConsistentRead を true に設定して Scan を使用します。Scan の実行中、DynamoDB ストリーム はテーブルで発生した追加の書き込みアクティビティをすべて記録します。Scan が完了したら、ストリームからテーブルへの書き込みアクティビティを適用できます。

注記

ConsistentReadtrue に設定した Scan オペレーションでは、ConsistentRead をデフォルト値 (false) のままにした場合と比較して、2 倍の読み込みキャパシティーユニットが使用されます。

並列スキャン

デフォルトでは、Scan オペレーションはデータを連続的に処理します。DynamoDB は 1 MB の増分でアプリケーションにデータを返し、アプリケーションは追加の Scan オペレーションを実行して、次の 1 MB 分のデータを取り出します。

スキャンされるテーブルまたはインデックスが大きいほど、Scan の完了に要する時間は長くなります。さらに、シーケンシャルな Scan では、プロビジョニングされた読み込みスループットキャパシティーが完全に利用されない場合があります。DynamoDB がサイズの大きいテーブルのデータを複数の物理パーティションに分散しても、Scan オペレーションでは一度に 1 つのパーティションしか読み込むことができません。そのため Scan のスループットは、単一のパーティションの最大スループットによって制限されます。

これらの問題に対処するために、Scan オペレーションではテーブルまたはセカンダリインデックスを複数のセグメントに論理的に分割して、複数のアプリケーションワーカーがセグメントに対する並列スキャンを行うことができます。各ワーカーは、スレッド(マルチスレッドをサポートするプログラミング言語を使用)またはオペレーティングシステムのプロセスにすることができます。並列スキャンを実行するには、各ワーカーが次のパラメータを使用して、別個に Scan リクエストを行います。

  • Segment — 特定のワーカーがスキャンするセグメント。各ワーカーは Segment にそれぞれ異なる値を指定します。

  • TotalSegments — 並列スキャンの対象となるセグメントの合計数。この値は、アプリケーションで使用されるワーカーの数と同じでなければなりません。

次の図は、マルチスレッドアプリケーションが 3 段階の並列処理で実行する並列 Scan を示しています。

この図では、アプリケーションが 3 つのスレッドをスポーンして、各スレッドに番号を割り当てています(セグメントはゼロベースであるため、最初の数字は必ず 0 になります)。各スレッドは Scan リクエストを発行し、Segment を指定された数値に設定して、TotalSegments を 3 に設定します。各スレッドは指定されたセグメントをスキャンし、一度に 1 MB のデータを取り出し、アプリケーションのメインスレッドにデータを返します。

Segment および TotalSegments の値は個々の Scan リクエストに適用され、また異なる値をいつでも使用できます。これらの値、および使用するワーカー数を決定するには、アプリケーションのパフォーマンスが最高になるまで実験を行う必要があるかもしれません。

注記

多数のワーカーで行う並列スキャンでは、スキャンされるテーブルまたはインデックスのためにプロビジョニングされたスループットがすぐにすべて使用されます。テーブルまたはインデックスでも他のアプリケーションからの重い読み込みや書き込みが発生させる場合は、このようなスキャンは避けるのが最善です。

リクエストごとに返されるデータの量を制御するには、Limit パラメータを使用します。それによって、1 つのワーカーがプロビジョニングされたスループットを使い果たして、他のワーカーが制約を受ける状況が避けられます。