Ma table est d'environ 220Mo avec 250K enregistrements. J'essaie d'extraire toutes ces données en python. Je me rends compte qu'il doit s'agir d'un traitement par lots fragmenté et bouclé, mais je ne suis pas sûr de savoir comment définir les lots de manière à ce que les précédents soient laissés de côté.
Est-il possible de filtrer mon scan? D'après ce que j'ai lu, le filtrage a lieu après le chargement et le chargement s'arrête à 1 Mo, donc je ne serais pas en mesure d'analyser de nouveaux objets.
Toute aide serait appréciée.
import boto3
dynamodb = boto3.resource('dynamodb',
aws_session_token = aws_session_token,
aws_access_key_id = aws_access_key_id,
aws_secret_access_key = aws_secret_access_key,
region_name = region
)
table = dynamodb.Table('widgetsTableName')
data = table.scan()
Je pense que le documentation Amazon DynamoDB en ce qui concerne l'analyse de table répond à votre question.
En bref, vous devrez vérifier LastEvaluatedKey
dans la réponse. Voici un exemple utilisant votre code:
import boto3
dynamodb = boto3.resource('dynamodb',
aws_session_token=aws_session_token,
aws_access_key_id=aws_access_key_id,
aws_secret_access_key=aws_secret_access_key,
region_name=region
)
table = dynamodb.Table('widgetsTableName')
response = table.scan()
data = response['Items']
while 'LastEvaluatedKey' in response:
response = table.scan(ExclusiveStartKey=response['LastEvaluatedKey'])
data.extend(response['Items'])
boto3 propose des paginateurs qui gèrent tous les détails de la pagination pour vous. Here est la page de documentation du paginateur de numérisation. En gros, vous l'utiliseriez comme ceci:
import boto3
client = boto3.client('dynamodb')
paginator = client.get_paginator('scan')
for page in paginator.paginate():
# do something
Décrivant la réponse de Jordon Phillips, voici comment passer un FilterExpression
avec la pagination:
import boto3
client = boto3.client('dynamodb')
paginator = client.get_paginator('scan')
operation_parameters = {
'TableName': 'foo',
'FilterExpression': 'bar > :x AND bar < :y',
'ExpressionAttributeValues': {
':x': {'S': '2017-01-31T01:35'},
':y': {'S': '2017-01-31T02:08'},
}
}
page_iterator = paginator.paginate(**operation_parameters)
for page in page_iterator:
# do something
Code pour supprimer le type de format dynamodb comme indiqué par @kungphu.
import boto3
from boto3.dynamodb.types import TypeDeserializer
from boto3.dynamodb.transform import TransformationInjector
client = boto3.client('dynamodb')
paginator = client.get_paginator('query')
service_model = client._service_model.operation_model('Query')
trans = TransformationInjector(deserializer = TypeDeserializer())
for page in paginator.paginate():
trans.inject_attribute_value_output(page, service_model)
Il s'avère que Boto3 capture la "LastEvaluatedKey" dans la réponse renvoyée. Ceci peut être utilisé comme point de départ pour une analyse:
data= table.scan(
ExclusiveStartKey=data['LastEvaluatedKey']
)
Je prévois de créer une boucle autour de cela jusqu'à ce que les données renvoyées ne soient plus que ExclusiveStartKey
La réponse de Vincent concernant la transformation appliquée à LastEvaluatedKey et la pagination me posait problème. Résolu comme suit:
import boto3
from boto3.dynamodb.types import TypeDeserializer
from boto3.dynamodb.transform import TransformationInjector
client = boto3.client('dynamodb')
paginator = client.get_paginator('scan')
operation_model = client._service_model.operation_model('Scan')
trans = TransformationInjector(deserializer = TypeDeserializer())
operation_parameters = {
'TableName': 'tablename',
}
items = []
for page in paginator.paginate(**operation_parameters):
has_last_key = 'LastEvaluatedKey' in page
if has_last_key:
last_key = page['LastEvaluatedKey'].copy()
trans.inject_attribute_value_output(page, operation_model)
if has_last_key:
page['LastEvaluatedKey'] = last_key
items.extend(page['Items'])
DynamoDB limite la méthode scan
à 1 Mo de données par analyse.
Documentation: https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/dynamodb.html# DynamoDB.Client.scan
Voici un exemple de boucle permettant d'obtenir toutes les données d'une table DynamoDB à l'aide de LastEvaluatedKey
:
import boto3
dynamodb = boto3.resource('dynamodb')
table = dynamodb.Table('your_table_name')
has_items = True
last_key = False
while has_items:
if last_key:
data = table.scan(ExclusiveStartKey=last_key)
else:
data = table.scan()
if 'LastEvaluatedKey' in data:
has_items = True
last_key = data['LastEvaluatedKey']
else:
has_items = False
last_key = False
# TODO do something with data['Items'] here.
Les deux approches suggérées ci-dessus ont toutes deux des problèmes: écrire du code long et répétitif qui gère la pagination de manière explicite dans une boucle, ou utiliser des paginateurs Boto avec des sessions de bas niveau et renoncer aux avantages des objets Boto de niveau supérieur.
Une solution utilisant Python) pour fournir une abstraction de haut niveau permet d'utiliser des méthodes Boto de niveau supérieur, tout en masquant la complexité de la pagination AWS:
import itertools
import typing
def iterate_result_pages(function_returning_response: typing.Callable, *args, **kwargs) -> typing.Generator:
"""A wrapper for functions using AWS paging, that returns a generator which yields a sequence of items for
every response
Args:
function_returning_response: A function (or callable), that returns an AWS response with 'Items' and optionally 'LastEvaluatedKey'
This could be a bound method of an object.
Returns:
A generator which yields the 'Items' field of the result for every response
"""
response = function_returning_response(*args, **kwargs)
yield response["Items"]
while "LastEvaluatedKey" in response:
kwargs["ExclusiveStartKey"] = response["LastEvaluatedKey"]
response = function_returning_response(*args, **kwargs)
yield response["Items"]
return
def iterate_paged_results(function_returning_response: typing.Callable, *args, **kwargs) -> typing.Iterator:
"""A wrapper for functions using AWS paging, that returns an iterator of all the items in the responses.
Items are yielded to the caller as soon as they are received.
Args:
function_returning_response: A function (or callable), that returns an AWS response with 'Items' and optionally 'LastEvaluatedKey'
This could be a bound method of an object.
Returns:
An iterator which yields one response item at a time
"""
return itertools.chain.from_iterable(iterate_result_pages(function_returning_response, *args, **kwargs))
# Example, assuming 'table' is a Boto DynamoDB table object:
all_items = list(iterate_paged_results(ProjectionExpression = 'my_field'))