Query または Scan オペレーションを使用して Amazon DynamoDB テーブルから項目を取得しても、レスポンスから完全な結果が返されません。
解決策
この問題は、次の 2 つの条件が原因で発生します。
- 最初の Query または Scan 操作では、レスポンスに LastEvaluatedKey が含まれます。
- 後続の操作を実行するための次のリクエストでは、このキーを ExclusiveStartKey として使用しませんでした。
この問題を解決するには、DynamoDB テーブルにページネーションを実装します。ページネーションとは、前のリクエストが不完全な場合に、それ以降のリクエストを送信して続行するプロセスです。DynamoDB の Query または Scan オペレーションでは、不完全な結果が返され、結果セット全体を取得するために後続のリクエストが必要になることがあります。これは、DynamoDB が Query または Scan オペレーションの結果をページ分割し、1 回のオペレーションで最大 1 MB のデータを返すためです。DynamoDB では、データの最大数はハードリミットです。ページネーションでは、Scan 操作と Query 操作の結果が 1 MB 以下のデータページに分割されます。
Amazon DynamoDB にページネーションを実装するには、組み込みのページネーション機能を使用します。次の例のようなコマンドを実行します。
use DynamoDB.Paginator.Query.paginate
client = boto3.client("dynamodb")
paginator = client.get_paginator("scan")
params = {}
for page in paginator.paginate(params):
# do something
結果をページ分割して、一度に 1 ページずつ取得することもできます。結果に LastEvaluatedKey 要素が含まれているかどうかを確認するには、Scan または Query 操作による低レベルの結果を確認します。残りの結果を取得するには、同じパラメータで別の Scan または Query 操作を使用してください。2 番目の操作では、LastEvaluatedKey を ExclusiveStartKey パラメータとして使用します。結果に LastEvaluatedKey 値が含まれていない場合、取得する項目はありません。
詳細については、「テーブルクエリ結果のページネーション」および「結果のページネーション」を参照してください。
LastEvaluatedKey を使用して Boto3 でページネーションを実装するには、次の例のようなコマンドを実行します。
from __future__ import print_function # Python 2/3 compatibility
import boto3
from botocore.exceptions import ClientError
# Create Client
session = boto3.session.Session()
dynamoDbClient = session.client('dynamodb')
table_name = 'AmazonBins'
# Track number of Items read
item_count = 0
try:
# Get the first 1MB of data
response = dynamoDbClient.scan(
TableName=table_name
)
except ClientError as error:
print("Something went wrong: ")
print(error.response['ResponseMetadata'])
# Track number of Items read
item_count += len(response['Items'])
# Paginate returning up to 1MB of data for each iteration
while 'LastEvaluatedKey' in response:
try:
response = dynamoDbClient.scan(
TableName=table_name,
ExclusiveStartKey=response['LastEvaluatedKey']
)
# Track number of Items read
item_count += len(response['Items'])
except ClientError as error:
print("Something went wrong: ")
print(error.response['ResponseMetadata'])
print("Total number of items found: {}".format(item_count))