Programación de Amazon DynamoDB con Python y Boto3
Esta guía ofrece orientación a los programadores que desean utilizar Amazon DynamoDB con Python. Obtenga información sobre las distintas capas de abstracción, la configuración de la administración, la gestión de errores, el control de las políticas de reintentos, la gestión de keep-alive y mucho más.
Temas
Acerca de Boto
Puede acceder a DynamoDB desde Python desde el SDK oficial de AWS para Python, conocido comúnmente como Boto3. El nombre Boto proviene de un delfín de agua dulce originario del río Amazonas. La biblioteca Boto3 es la tercera versión principal de la biblioteca publicada por primera vez en 2015. La biblioteca Boto3 es bastante grande, ya que es compatible con todos los servicios de AWS, no solo con DynamoDB. Esta guía trata únicamente las partes de Boto3 relevantes para DynamoDB.
AWS actualiza y publica Boto como proyecto de código abierto alojado en GitHub, que está dividido en dos paquetes: Botocore
-
Botocore proporciona la funcionalidad de bajo nivel. En Botocore encontrará las clases de cliente, sesión, credenciales, configuración y excepción.
-
Boto3 se basa en Botocore y ofrece una interfaz más cercana a Python y de nivel superior. En concreto, expone una tabla de DynamoDB como recurso y ofrece una interfaz más sencilla y elegante en comparación con la interfaz de cliente orientada a servicios de nivel inferior.
Dado que estos proyectos están alojados en GitHub, puede ver el código fuente, realizar un seguimiento de los problemas pendientes o enviar sus propios problemas.
Uso de la documentación de Boto
Comience a utilizar la documentación de Boto con los siguientes recursos:
-
Comience con la sección Quickstart
, que proporciona un punto de partida sólido para instalar el paquete. Navegue hasta allí para obtener instrucciones sobre cómo instalar Boto3 si aún no lo ha instalado (Boto3 suele estar disponible automáticamente en los servicios de AWS tales como AWS Lambda). -
Después, céntrese en la documentación de la guía de DynamoDB
donde se explica cómo realizar las actividades básicas de DynamoDB: crear y eliminar una tabla, manipular elementos, ejecutar operaciones por lotes, ejecutar una consulta y realizar un análisis. Los ejemplos utilizan la interfaz de recursos. Cuando vea boto3.resource('dynamodb')
, significa que está utilizando la interfaz de recursos de nivel superior. -
Tras leer la guía, puede consultar la referencia de DynamoDB
. Esta página de aterrizaje proporciona una lista exhaustiva de las clases y los métodos disponibles. En la parte superior, verá la clase DynamoDB.Client
que proporciona un acceso de bajo nivel a todas las operaciones del plano de control y del plano de datos. En la parte inferior, verá la claseDynamoDB.ServiceResource
. Esta es la interfaz de Python de nivel superior. Con ella, puede crear una tabla, realizar operaciones por lotes entre tablas u obtener una instanciaDynamoDB.ServiceResource.Table
para acciones específicas de una tabla.
Comprensión de las capas de abstracción de clientes y recursos
Las dos interfaces con las que trabajará son la interfaz de cliente y la interfaz de recursos.
-
La interfaz de cliente de bajo nivel proporciona una asignación uno a uno con la API del servicio subyacente. Todas las API que ofrece DynamoDB están disponibles a través del cliente. Esto significa que la interfaz de cliente puede proporcionar toda la funcionalidad, pero suele ser más detallada y su uso es más complejo.
-
La interfaz de recursos de nivel superior no proporciona una asignación uno a uno de la API del servicio subyacente. Sin embargo, proporciona métodos que facilitan el acceso al servicio, como
batch_writer
.
A continuación, se muestra un ejemplo de cómo insertar un elemento mediante la interfaz de cliente. Observe cómo todos los valores se transfieren como un mapa: la clave indica el tipo («S» para cadena, «N» para número) y el valor es de cadena. Este es el formato JSON de DynamoDB.
import boto3 dynamodb = boto3.client('dynamodb') dynamodb.put_item( TableName='YourTableName', Item={ 'pk': {'S': 'id#1'}, 'sk': {'S': 'cart#123'}, 'name': {'S': 'SomeName'}, 'inventory': {'N': '500'}, # ... more attributes ... } )
A continuación se muestra la misma operación PutItem
con la interfaz de recursos. La escritura de datos está implícita:
import boto3 dynamodb = boto3.resource('dynamodb') table = dynamodb.Table('YourTableName') table.put_item( Item={ 'pk': 'id#1', 'sk': 'cart#123', 'name': 'SomeName', 'inventory': 500, # ... more attributes ... } )
Si es necesario, puede realizar la conversión entre JSON normal y JSON de DynamoDB mediante las clases TypeSerializer
y TypeDeserializer
que se proporcionan con Boto3:
def dynamo_to_python(dynamo_object: dict) -> dict: deserializer = TypeDeserializer() return { k: deserializer.deserialize(v) for k, v in dynamo_object.items() } def python_to_dynamo(python_object: dict) -> dict: serializer = TypeSerializer() return { k: serializer.serialize(v) for k, v in python_object.items() }
A continuación, se muestra cómo realizar una consulta desde la interfaz de cliente. La consulta se expresa como constructo de JSON. Utiliza una cadena KeyConditionExpression
que requiere sustituir las variables para gestionar cualquier posible conflicto con las palabras clave:
import boto3 client = boto3.client('dynamodb') # Construct the query response = client.query( TableName='YourTableName', KeyConditionExpression='pk = :pk_val AND begins_with(sk, :sk_val)', FilterExpression='#name = :name_val', ExpressionAttributeValues={ ':pk_val': {'S': 'id#1'}, ':sk_val': {'S': 'cart#'}, ':name_val': {'S': 'SomeName'}, }, ExpressionAttributeNames={ '#name': 'name', } )
La misma operación de consulta con la interfaz de recursos se puede acortar y simplificar:
import boto3 from boto3.dynamodb.conditions import Key, Attr dynamodb = boto3.resource('dynamodb') table = dynamodb.Table('YourTableName') response = table.query( KeyConditionExpression=Key('pk').eq('id#1') & Key('sk').begins_with('cart#'), FilterExpression=Attr('name').eq('SomeName') )
Por último, imagine que desea saber el tamaño aproximado de una tabla (es decir, los metadatos que se guardan en la tabla y que se actualizan aproximadamente cada 6 horas). Con la interfaz de cliente, realiza una operación describe_table()
y extrae la respuesta de la estructura JSON devuelta:
import boto3 dynamodb = boto3.client('dynamodb') response = dynamodb.describe_table(TableName='YourTableName') size = response['Table']['TableSizeBytes']
Con la interfaz de recursos, la tabla realiza la operación de descripción de forma implícita y presenta los datos directamente como un atributo:
import boto3 dynamodb = boto3.resource('dynamodb') table = dynamodb.Table('YourTableName') size = table.table_size_bytes
nota
Al plantearse si desarrollar con la interfaz de cliente o de recursos, tenga en cuenta que no se añadirán nuevas características a la interfaz de recursos según se indica en la documentación del recurso
Uso del recurso de tabla batch_writer
batch_writer
es una opción muy cómoda que solo está disponible en el recurso de tabla de nivel superior. DynamoDB admite operaciones de escritura por lotes, lo que permite realizar hasta 25 operaciones de inserción o eliminación en una solicitud de red. Este tipo de procesamiento por lotes mejora la eficiencia al minimizar los viajes de ida y vuelta de la red.
En la biblioteca cliente de bajo nivel, se utiliza la operación client.batch_write_item()
para ejecutar lotes. Debe dividir manualmente el trabajo en lotes de 25. Después de cada operación, también debe solicitar que se envíe una lista de los elementos sin procesar (algunas de las operaciones de escritura pueden realizarse correctamente y otras pueden fallar). A continuación, debe volver a transferir los elementos no procesados a una operación batch_write_item()
posterior. Hay una gran cantidad de código reutilizable.
El método Table.batch_writer
dynamodb = boto3.resource('dynamodb') table = dynamodb.Table('YourTableName') movies = # long list of movies in {'pk': 'val', 'sk': 'val', etc} format with table.batch_writer() as writer: for movie in movies: writer.put_item(Item=movie)
Ejemplos de código adicionales que exploran las capas de cliente y de recursos
También puede consultar los siguientes repositorios de ejemplos de código, que exploran el uso de las distintas funciones, tanto con el cliente como con el recurso:
Comprensión sobre la interacción de los objetos Client y Resource con las sesiones y los subprocesos
El objeto Resource no es seguro para los subprocesos y no debe compartirse entre subprocesos o procesos. Consulte la guía sobre Resource
El objeto Client, por el contrario, generalmente es seguro para los subprocesos, excepto en el caso de las características avanzadas específicas. Consulte la guía sobre Clients
El objeto Session no es seguro para los subprocesos. Por lo tanto, cada vez que cree un Client o Resource en un entorno con varios subprocesos, primero debe crear una nueva Session y, a continuación, crear el Client o el Resource a partir de la Session. Consulte la guía sobre Sessions
Cuando llama al boto3.resource()
, está utilizando la Session predeterminada de forma implícita. Esto resulta práctico para escribir código de un solo subproceso. Al escribir código con varios subprocesos, primero deberá construir una nueva Session para cada subproceso y, a continuación, recuperar el recurso de esa Session:
# Explicitly create a new Session for this thread session = boto3.Session() dynamodb = session.resource('dynamodb')
Personalización del objeto Config
Al crear un objeto Client o Resource, puede transferir parámetros con nombres opcionales para personalizar el comportamiento. El parámetro denominado config
desbloquea una variedad de funciones. Se trata de una instancia botocore.client.Config
y la documentación de referencia de Config
nota
Puede modificar muchos de estos ajustes de comportamiento en el nivel de Session, en el archivo de configuración de AWS o como variables de entorno.
Config para tiempos de espera
Uno de los usos de una configuración personalizada es ajustar los comportamientos de la red:
-
connect_timeout (flotante o entero): tiempo en segundos que transcurre hasta que se produzca una excepción de tiempo de espera al intentar establecer una conexión. El valor predeterminado es de 60 segundos.
-
read_timeout (flotante o entero): tiempo en segundos que transcurre hasta que se produzca una excepción de tiempo de espera al intentar leer una conexión. El valor predeterminado es de 60 segundos.
Los tiempos de espera de 60 segundos son excesivos para DynamoDB. Esto significa que un fallo transitorio en la red provocará un minuto de retardo hasta que el cliente pueda volver a intentarlo. El siguiente código acorta los tiempos de espera hasta un segundo:
import boto3 from botocore.config import Config my_config = Config( connect_timeout = 1.0, read_timeout = 1.0 ) dynamodb = boto3.resource('dynamodb', config=my_config)
Para obtener más información sobre los tiempos de espera, consulte Tuning AWS Java SDK HTTP request settings for latency-aware DynamoDB applications
Config para keep-alive
Si utiliza botocore 1.27.84 o posterior, también puede controlar el TCP Keep-Alive:
-
tcp_keepalive (booleano): activa la opción de conector TCP Keep-Alive que se usa al crear nuevas conexiones si está configurada en
True
(el valor predeterminado esFalse
). Solo está disponible a partir de la versión 1.27.84 de botocore.
Si se configura TCP Keep-Alive en True
, se pueden reducir las latencias medias. Este es un ejemplo de código que establece el valor de TCP Keep-Alive condicionalmente en true si tiene la versión de botocore correcta:
import botocore import boto3 from botocore.config import Config from distutils.version import LooseVersion required_version = "1.27.84" current_version = botocore.__version__ my_config = Config( connect_timeout = 0.5, read_timeout = 0.5 ) if LooseVersion(current_version) > LooseVersion(required_version): my_config = my_config.merge(Config(tcp_keepalive = True)) dynamodb = boto3.resource('dynamodb', config=my_config)
nota
TCP Keep-Alive no es lo mismo que HTTP Keep-Alive. Con TCP Keep-Alive, el sistema operativo subyacente envía paquetes pequeños a través de la conexión de socket para mantener la conexión activa y detectar inmediatamente cualquier caída. Con HTTP Keep-Alive, se reutiliza la conexión web integrada en el socket subyacente. HTTP Keep-Alive siempre está activado en boto3.
Hay un límite en cuanto al tiempo que se puede mantener activa una conexión inactiva. Considere la posibilidad de enviar solicitudes periódicas, tal vez cada minuto, si tiene una conexión inactiva pero quiere que la siguiente solicitud utilice una conexión ya establecida.
Config para reintentos
La configuración también acepta un diccionario llamado reintentos en el que puede especificar el comportamiento de reintentos que espera. Los reintentos se producen dentro del SDK cuando este recibe un error de tipo transitorio. Si se vuelve a intentar un error internamente (y el reintento genera una respuesta correcta), desde el punto de vista del código, no se trata de ningún error, sino de una latencia ligeramente elevada. Estos son los valores que puede especificar:
-
max_attempts: número entero que representa el número máximo de reintentos que se realizará en una sola solicitud. Por ejemplo, si establece este valor en 2, la solicitud se volverá a intentar como máximo dos veces después de la solicitud inicial. Si se establece en 0, no se intentará de nuevo después de la solicitud inicial.
-
total_max_attempts: número entero que representa el número total máximo de intentos que se realizará en una sola solicitud. Esto incluye la solicitud inicial, por lo que un valor de 1 indica que no se volverá a intentar ninguna solicitud. Si se proporcionan
total_max_attempts
ymax_attempts
,total_max_attempts
prevalece. Se prefieretotal_max_attempts
sobremax_attempts
porque se asigna a la variable de entorno deAWS_MAX_ATTEMPTS
y al valor del archivo de configuraciónmax_attempts
. -
mode: cadena que representa el tipo de modo de reintento que debe utilizar botocore. Los valores válidos son:
-
legacy: modo predeterminado. Espera 50 ms en el primer reintento y, a continuación, utiliza un retroceso exponencial con un factor base de 2. En el caso de DynamoDB, realiza un máximo de 10 intentos, a menos que se anule con lo anterior.
nota
Con un retroceso exponencial, el último intento esperará casi 13 segundos.
-
standard: se denomina estándar porque es más coherente con otros SDK de AWS. Este modo espera un período de tiempo aleatorio que va desde 0 ms hasta 1000 ms para el primer reintento. Si es necesario volver a intentarlo, selecciona otro tiempo aleatorio de 0 ms hasta 1000 ms y lo multiplica por 2. Si es necesario volver a intentarlo, realiza la misma selección aleatoria multiplicada por 4, y así sucesivamente. Cada espera tiene un límite de 20 segundos. Este modo realizará reintentos en caso de que se detecten más condiciones de fallo que el modo
legacy
. En el caso de DynamoDB, realiza un máximo de 3 intentos (a menos que se anule con lo anterior). -
adaptive: modo de reintento experimental que incluye la funcionalidad del modo estándar, pero añade una limitación automática del lado del cliente. Con la limitación de velocidad adaptativa, los SDK pueden ralentizar la velocidad a la que se envían las solicitudes para adaptarse mejor a la capacidad de los servicios de AWS. Se trata de un modo provisional cuyo comportamiento puede cambiar.
-
La definición ampliada de estos modos de reintento está disponible en la guía de reintentos
Este es un ejemplo en el que se utiliza explícitamente la política de reintentos legacy
con un máximo de 3 solicitudes en total (2 reintentos):
import boto3 from botocore.config import Config my_config = Config( connect_timeout = 1.0, read_timeout = 1.0, retries = { 'mode': 'legacy', 'total_max_attempts': 3 } ) dynamodb = boto3.resource('dynamodb', config=my_config)
Dado que DynamoDB es un sistema de alta disponibilidad y baja latencia, puede ser más agresivo con la velocidad de los reintentos de lo que permiten las políticas de reintentos integradas. Puede implementar su propia política de reintentos estableciendo el número máximo de intentos en 0, detectando usted mismo las excepciones y reintentándolo según convenga con su propio código, en lugar de depender de boto3 para realizar los reintentos implícitos.
Si administra su propia política de reintentos, se recomienda diferenciar entre limitaciones y errores:
-
Una limitación (indicada con una
ProvisionedThroughputExceededException
oThrottlingException
) representa un servicio en buen estado que le informa de que ha superado la capacidad de lectura o escritura en una tabla o partición de DynamoDB. Cada milisegundo que pasa, se dispone de un poco más de capacidad de lectura o escritura, por lo que puede volver a intentarlo rápidamente (por ejemplo, cada 50 ms) para intentar acceder a la capacidad recién liberada. Con las limitaciones no se requiere un retroceso exponencial, pues las limitaciones son ligeras para que DynamoDB las devuelva. Además, no se le cobra por solicitud. El retroceso exponencial asigna retardos más prolongados a los subprocesos de los clientes que ya han esperado más tiempo, lo que, estadísticamente, prolonga la p50 y la p99 hacia fuera. -
Un error (identificado con
InternalServerError
oServiceUnavailable
, entre otros) indica un problema transitorio con el servicio. Esto puede ser para toda la tabla o, posiblemente, solo para la partición desde la que está leyendo o escribiendo. En el caso de los errores, puede hacer una pausa más larga antes de volver a intentarlo, por ejemplo, 250 ms o 500 ms, y utilizar la fluctuación para escalonar los reintentos.
Config para un máximo de conexiones de grupo
Por último, la configuración le permite controlar el tamaño del grupo de conexiones:
-
max_pool_connections (entero): número máximo de conexiones que se debe mantener en un grupo de conexiones. Si no se especifica ningún valor, se utiliza el valor predeterminado 10.
Esta opción controla el número máximo de conexiones HTTP que se debe mantener agrupado para volverlas a utilizar. Se conserva un grupo diferente por sesión. Si prevé que se van a dirigir más de 10 subprocesos a los clientes o los recursos creados en la misma sesión, debería plantearse aumentarlo para que los subprocesos no tengan que esperar a que otros subprocesos utilicen una conexión agrupada.
import boto3 from botocore.config import Config my_config = Config( max_pool_connections = 20 ) # Setup a single session holding up to 20 pooled connections session = boto3.Session(my_config) # Create up to 20 resources against that session for handing to threads # Notice the single-threaded access to the Session and each Resource resource1 = session.resource('dynamodb') resource2 = session.resource('dynamodb') # etc
Gestión de errores
No todas las excepciones de servicio de AWS se definen estáticamente en Boto3. Esto se debe a que los errores y las excepciones de los servicios de AWS varían ampliamente y están sujetos a cambios. Boto3 agrupa todas las excepciones del servicio como un ClientError
y expone los detalles como un JSON estructurado. Por ejemplo, una respuesta de error podría estructurarse de la siguiente manera:
{ 'Error': { 'Code': 'SomeServiceException', 'Message': 'Details/context around the exception or error' }, 'ResponseMetadata': { 'RequestId': '1234567890ABCDEF', 'HostId': 'host ID data will appear here as a hash', 'HTTPStatusCode': 400, 'HTTPHeaders': {'header metadata key/values will appear here'}, 'RetryAttempts': 0 } }
El código siguiente detecta cualquier excepción ClientError
y examina el valor de la cadena de Code
dentro del Error
para determinar qué acción se debe realizar:
import botocore import boto3 dynamodb = boto3.client('dynamodb') try: response = dynamodb.put_item(...) except botocore.exceptions.ClientError as err: print('Error Code: {}'.format(err.response['Error']['Code'])) print('Error Message: {}'.format(err.response['Error']['Message'])) print('Http Code: {}'.format(err.response['ResponseMetadata']['HTTPStatusCode'])) print('Request ID: {}'.format(err.response['ResponseMetadata']['RequestId'])) if err.response['Error']['Code'] in ('ProvisionedThroughputExceededException', 'ThrottlingException'): print("Received a throttle") elif err.response['Error']['Code'] == 'InternalServerError': print("Received a server error") else: raise err
Algunos códigos de excepción (pero no todos) se han materializado como clases de nivel superior. Puede optar por gestionarlos directamente. Cuando se utiliza la interfaz Client, estas excepciones se rellenan dinámicamente en el cliente y se detectan mediante la instancia de cliente, de la siguiente manera:
except ddb_client.exceptions.ProvisionedThroughputExceededException:
Cuando utilice la interfaz Resource, tendrá que usar .meta.client
para ir desde el recurso hasta el cliente subyacente para acceder a las excepciones, de la siguiente manera:
except ddb_resource.meta.client.exceptions.ProvisionedThroughputExceededException:
Puede generar la lista de tipos de excepciones materializadas de forma dinámica para consultarla:
ddb = boto3.client("dynamodb") print([e for e in dir(ddb.exceptions) if e.endswith('Exception') or e.endswith('Error')])
Al realizar una operación de escritura con una expresión de condición, puede solicitar que, si la expresión falla, se devuelva el valor del elemento en la respuesta de error.
try: response = table.put_item( Item=item, ConditionExpression='attribute_not_exists(pk)', ReturnValuesOnConditionCheckFailure='ALL_OLD' ) except table.meta.client.exceptions.ConditionalCheckFailedException as e: print('Item already exists:', e.response['Item'])
Para obtener más información sobre la gestión de errores y las excepciones:
-
La guía de boto3 sobre la gestión de errores
contiene más información sobre las técnicas de gestión de errores. -
En la sección sobre errores de programación de la guía para desarrolladores de DynamoDB se enumeran los errores que pueden producirse.
-
En la documentación de cada operación de la API se enumeran los errores que puede generar esa llamada (por ejemplo, BatchWriteItem).
Registro
La biblioteca boto3 se integra con el módulo de registro incluido de Python para hacer un seguimiento de lo que ocurre durante una sesión. Para controlar los niveles de registro, puede configurar el módulo de registro:
import logging logging.basicConfig(level=logging.INFO)
Esto configura el registrador raíz para registrar INFO
y los mensajes de nivel superior. Se ignorarán los mensajes de registro que sean menos graves que el nivel. Los niveles de registro son DEBUG
, INFO
, WARNING
, ERROR
y CRITICAL
. El valor predeterminado es WARNING
.
Los registradores en boto3 son jerárquicos. La biblioteca usa varios registradores diferentes y cada uno equivale a diferentes partes de la biblioteca. Puede controlar el comportamiento de cada uno de ellos por separado:
-
boto3: es el registrador principal del módulo boto3.
-
botocore: es el registrador principal del paquete botocore.
-
botocore.auth: se utiliza para registrar la creación de firmas de AWS para las solicitudes.
-
botocore.credentials: se utiliza para registrar el proceso de obtención y actualización de credenciales.
-
botocore.endpoint: se utiliza para registrar la creación de solicitudes antes de enviarlas a través de la red.
-
botocore.hooks: se utiliza para los eventos de registro desencadenados en la biblioteca.
-
botocore.loaders: se utiliza para registrar la carga de partes de los modelos de servicio de AWS.
-
botocore.parsers: se utiliza para registrar las respuestas del servicio de AWS antes de analizarlas.
-
botocore.retryhandler: se utiliza para registrar el procesamiento de los reintentos de solicitudes de servicio de AWS (modo heredado).
-
botocore.retryhandler: se utiliza para registrar el procesamiento de los reintentos de solicitudes de servicio de AWS (modo estándar o adaptativo).
-
botocore.utils: se utiliza para registrar diversas actividades en la biblioteca.
-
botocore.waiter: se utiliza para registrar la funcionalidad de los esperadores, que consultan un servicio de AWS hasta que se alcance un estado determinado.
Otras bibliotecas también registran. Internamente, boto3 utiliza la urllib3 de terceros para gestionar la conexión HTTP. Si la latencia es importante, puede observar sus registros para asegurarse de que su grupo se utiliza correctamente. Para ello, comprueba cuándo urllib3 establece una nueva conexión o cierra una que está inactiva.
-
urllib3.connectionpool: se utiliza para registrar los eventos de gestión de grupos de conexiones.
El siguiente fragmento de código establece la mayoría de los registros INFO
con el registro DEBUG
para el punto de conexión y la actividad del grupo de conexiones:
import logging logging.getLogger('boto3').setLevel(logging.INFO) logging.getLogger('botocore').setLevel(logging.INFO) logging.getLogger('botocore.endpoint').setLevel(logging.DEBUG) logging.getLogger('urllib3.connectionpool').setLevel(logging.DEBUG)
Enlaces de eventos
Botocore emite eventos durante varias partes de su ejecución. Puede registrar controladores para estos eventos de modo que cada vez que se emita un evento, se llame a su controlador. Esto le permite ampliar el comportamiento de botocore sin tener que modificar las partes internas.
Por ejemplo, supongamos que quiere saber todas las veces que se llama a una operación PutItem
en cualquier tabla de DynamoDB de su aplicación. Puede registrarse en el evento 'provide-client-params.dynamodb.PutItem'
para detectar y registrar cada vez que se invoque una operación PutItem
en la sesión asociada. A continuación se muestra un ejemplo:
import boto3 import botocore import logging def log_put_params(params, **kwargs): if 'TableName' in params and 'Item' in params: logging.info(f"PutItem on table {params['TableName']}: {params['Item']}") logging.basicConfig(level=logging.INFO) session = boto3.Session() event_system = session.events # Register our interest in hooking in when the parameters are provided to PutItem event_system.register('provide-client-params.dynamodb.PutItem', log_put_params) # Now, every time you use this session to put an item in DynamoDB, # it will log the table name and item data. dynamodb = session.resource('dynamodb') table = dynamodb.Table('YourTableName') table.put_item( Item={ 'pk': '123', 'sk': 'cart#123', 'item_data': 'YourItemData', # ... more attributes ... } )
Dentro del controlador puede incluso manipular los parámetros mediante programación para cambiar el comportamiento:
params['TableName'] = "NewTableName"
Para obtener más información sobre los eventos, consulte la documentación de botocore sobre eventos
La paginación y el paginador
Algunas solicitudes, como Query y Scan, limitan el tamaño de los datos que se devuelven en una sola solicitud y requieren que realice solicitudes repetidas para abrir las páginas siguientes.
Puede controlar el número máximo de elementos que se debe leer en cada página con el parámetro limit
. Por ejemplo, puede usar limit
para recuperar solo los últimos 10 elementos. Tenga en cuenta que este límite indica cuánto debe leerse de la tabla antes de aplicar un filtro. No hay forma de especificar que quiere exactamente 10 después de filtrar; solo puede controlar el recuento previo al filtro y comprobarlo del lado del cliente cuando haya obtenido realmente 10. Cada respuesta tiene siempre un tamaño máximo de 1 MB, sin importar el límite.
Si la respuesta incluye una LastEvaluatedKey
, significa que la respuesta ha finalizado porque ha alcanzado un límite de recuento o tamaño. Esta clave es la última clave evaluada para esa respuesta. Puede recuperar esta LastEvaluatedKey
y pasarla a una llamada de seguimiento como ExclusiveStartKey
para que lea el siguiente fragmento desde ese punto de partida. Si no se devuelve ninguna LastEvaluatedKey
, significa que no hay más elementos que coincidan con la consulta o el análisis.
Este es un ejemplo sencillo (con la interfaz de recursos, pero la interfaz de cliente sigue el mismo patrón) en el que se leen como máximo 100 elementos por página y se repite hasta que se hayan leído todos los elementos.
import boto3 dynamodb = boto3.resource('dynamodb') table = dynamodb.Table('YourTableName') query_params = { 'KeyConditionExpression': Key('pk').eq('123') & Key('sk').gt(1000), 'Limit': 100 } while True: response = table.query(**query_params) # Process the items however you like for item in response['Items']: print(item) # No LastEvaluatedKey means no more items to retrieve if 'LastEvaluatedKey' not in response: break # If there are possibly more items, update the start key for the next page query_params['ExclusiveStartKey'] = response['LastEvaluatedKey']
boto3 puede hacerlo por usted con la opción Paginators. Sin embargo, solo funciona con la interfaz Client. Este es el código reescrito para usar Paginators:
import boto3 dynamodb = boto3.client('dynamodb') paginator = dynamodb.get_paginator('query') query_params = { 'TableName': 'YourTableName', 'KeyConditionExpression': 'pk = :pk_val AND sk > :sk_val', 'ExpressionAttributeValues': { ':pk_val': {'S': '123'}, ':sk_val': {'N': '1000'}, }, 'Limit': 100 } page_iterator = paginator.paginate(**query_params) for page in page_iterator: # Process the items however you like for item in page['Items']: print(item)
Para obtener más información, consulte la guía sobre Paginators
nota
Paginators también tiene sus propias opciones de configuración denominadas MaxItems
, StartingToken
y PageSize
. Para paginar con DynamoDB, debe ignorar esta configuración.
Esperadores
Los esperadores ofrecen la posibilidad de esperar a que se complete algo antes de continuar. Por el momento, solo permiten que se espere hasta que se cree o elimine una tabla. En segundo plano, el esperador realiza una comprobación cada 20 segundos hasta 25 veces. Puede hacerlo usted mismo, pero usar un esperador es más elegante a la hora de escribir de forma automática.
Este código muestra cómo esperar a que se cree una tabla en particular:
# Create a table, wait until it exists, and print its ARN response = client.create_table(...) waiter = client.get_waiter('table_exists') waiter.wait(TableName='YourTableName') print('Table created:', response['TableDescription']['TableArn']
Para obtener más información, consulte la guía sobre Waiters