DynamoDB BatchGetItem en Python (boto3)
batch_get_item récupère jusqu'à 100 éléments par clé primaire en une seule requête. Le while request_items: du bloc ci-dessous, c'est tout l'idiome boto3 : DynamoDB rend les restes dans une réponse réussie, et un dict vide est falsy, donc la boucle se termine d'elle-même. Les limites et les règles de résultat partiel sont dans les opérations batch dans DynamoDB ; cette page parle de l'appel boto3 et des erreurs qu'il lève.
Code
import time
import boto3
client = boto3.client("dynamodb")
request_items = {
"Music": {
"Keys": [
{"Artist": {"S": "Arturo Sandoval"}, "SongTitle": {"S": "Cubano Chant"}},
{"Artist": {"S": "Arturo Sandoval"}, "SongTitle": {"S": "A Mis Abuelos"}},
{"Artist": {"S": "Ella Fitzgerald"}, "SongTitle": {"S": "Misty"}},
]
}
}
items = []
attempt = 0
while request_items:
response = client.batch_get_item(RequestItems=request_items)
items.extend(response["Responses"].get("Music", []))
# A partial result is NOT an error: throttling, a >16 MB response, or an
# internal failure returns the leftovers in UnprocessedKeys. Retry them
# with exponential backoff.
request_items = response["UnprocessedKeys"]
if request_items:
attempt += 1
time.sleep(min(0.1 * 2**attempt, 5))
print(f"Fetched {len(items)} items")Explication
response["UnprocessedKeys"]est toujours là. Sur un batch entièrement servi, la clé existe et contient{}:request_items = response["UnprocessedKeys"]est donc sûr à indexer, et c'est le dict vide falsy qui met fin auwhile. C'estResponsesqui demande de la prudence : une table dont toutes les clés sont manquantes en est absente, d'où le.get("Music", [])du bloc.ConsistentReadetProjectionExpressionse placent dans le dict propre à chaque table, à côté de"Keys", et non à côté deRequestItems. boto3 enverra volontiers une clé mal placée et laissera le service la rejeter.- C'est le client bas niveau, donc les valeurs sont du JSON DynamoDB (
{"S": ...},{"N": ...}). L'API resource exposebatch_get_itemsur le ServiceResource, pas surTable.boto3.resource("dynamodb").batch_get_item(...)prend des valeurs Python natives ;table.batch_get_itemn'existe pas. Cette asymétrie surprend ceux qui y viennent après avoir utilisétable.batch_writer(), qui est, lui, une méthode deTable. - Le backoff ne s'applique qu'à
UnprocessedKeys. UneValidationExceptionest un bug dans la requête, et la réessayer ne fait que brûler du temps.
Les deux erreurs que cet appel lève, telles quelles
Les deux sont des fautes côté client qu'aucune reprise ne corrige, et les deux remontent comme une simple botocore.exceptions.ClientError. Contre DynamoDB Local 3.3.0, str(e) :
An error occurred (ValidationException) when calling the BatchGetItem operation: Too many items requested for the BatchGetItem call
An error occurred (ValidationException) when calling the BatchGetItem operation: Provided list of item keys contains duplicatesLa première, ce sont 101 clés ; la seconde, la même clé listée deux fois. Note ce que tu ne peux pas écrire pour les attraper :
except client.exceptions.ValidationException: # AttributeErrorbotocore modélise 34 classes d'exception nommées sur le client DynamoDB, et ValidationException n'en fait pas partie. ConditionalCheckFailedException et ProvisionedThroughputExceededException, si — c'est pour ça que la page sur l'écriture conditionnelle peut attraper par classe alors que celle-ci ne le peut pas. Il existe même une DuplicateItemException modélisée, et ce n'est pas ce que te donne une clé dupliquée dans un batch. Une lecture batch doit donc brancher sur le code :
except ClientError as e:
if e.response["Error"]["Code"] == "ValidationException":
raise # a bug in the request; retrying will not helpLe cas de la clé dupliquée est celui qui mord en vrai, parce qu'une liste de clés assemblée depuis un résultat de Query ou depuis une table de jointure comporte naturellement des répétitions. Déduplique avant d'envoyer, en te rappelant que deux dicts ne sont égaux que si chaque attribut de clé correspond.
La taille est l'autre raison pour laquelle un batch de 100 ne reste pas un batch de 100 : chaque élément est arrondi au supérieur à 4 KB pour la facturation et compté dans les 16 MB de la réponse, si bien que 100 éléments de 300 KB reviennent à environ 52, le reste étant dans UnprocessedKeys. Le calculateur de taille d'élément te donne le chiffre par élément à multiplier.
Pour relire un ensemble de clés et inspecter ce qui revient avant d'écrire la boucle, télécharge DynoTable.
Exemples liés
- DynamoDB BatchGetItem en Node.js — la même lecture batch avec l'AWS SDK v3.
- DynamoDB BatchGetItem avec l'AWS CLI — la même lecture batch depuis le shell.
- DynamoDB GetItem en Python — la lecture d'un seul élément que celle-ci regroupe.
- Les opérations batch dans DynamoDB — limites, échec partiel, et quand le batch est rentable.
- "Too many items requested for the BatchGetItem call" — plus de 100 clés dans une seule requête.
- "Provided list of item keys contains duplicates" — la même clé deux fois dans un batch.
Références
- BatchGetItem — Amazon DynamoDB API Reference
- DynamoDB.Client.batch_get_item — Boto3 documentation
- Error handling with DynamoDB — Amazon DynamoDB Developer Guide
Dernière vérification le 2026-07-28 par rapport à la documentation officielle AWS liée ci-dessus.