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 au while. C'est Responses qui demande de la prudence : une table dont toutes les clés sont manquantes en est absente, d'où le .get("Music", []) du bloc.
  • ConsistentRead et ProjectionExpression se placent dans le dict propre à chaque table, à côté de "Keys", et non à côté de RequestItems. 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 expose batch_get_item sur le ServiceResource, pas sur Table. boto3.resource("dynamodb").batch_get_item(...) prend des valeurs Python natives ; table.batch_get_item n'existe pas. Cette asymétrie surprend ceux qui y viennent après avoir utilisé table.batch_writer(), qui est, lui, une méthode de Table.
  • Le backoff ne s'applique qu'à UnprocessedKeys. Une ValidationException est 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 duplicates

La 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:  # AttributeError

botocore 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 help

Le 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

Références

Dernière vérification le 2026-07-28 par rapport à la documentation officielle AWS liée ci-dessus.

Travaille avec DynamoDB sans la Console

Un client de bureau rapide pour DynamoDB qui exécute le vrai SQL que DynamoDB ne peut pas — JOINs, GROUP BY, agrégations — avec édition visuelle et un agent IA sur tes propres clés Bedrock.

Essai gratuit de 30 jours, sans carte bancaire — ensuite la formule Gratuit, sans limite de durée.