Quando você precisa consultar dados recentes em um prazo específico, a exigência do DynamoDB de fornecer uma chave de partição para a maioria das operações de leitura pode ser um desafio. Para abordar esse cenário, você pode implementar um padrão de consulta eficaz usando uma combinação de fragmentação de gravação e um índice secundário global (GSI).
Essa abordagem permite que você recupere e analise dados sensíveis ao tempo de forma eficiente sem realizar verificações completas da tabela, o que pode consumir muitos recursos e ser caro. Ao projetar estrategicamente a estrutura e a indexação da tabela, é possível criar uma solução flexível que seja compatível com a recuperação de dados baseada no tempo, mantendo o desempenho ideal.
Tópicos
Padrão de design
Ao trabalhar com o DynamoDB, é possível superar os desafios de recuperação de dados baseada no tempo implementando um padrão sofisticado que combina fragmentação de gravação e índices secundários globais para permitir consultas flexíveis e eficientes em janelas de dados recentes.
Estrutura da tabela
Chave de partição (PK): “Username”
Estrutura do GSI
Chave de partição do GSI (PK_GSI): “ShardNumber#”
Chave de classificação do GSI (SK_GSI): carimbo de data/hora em ISO 8601 (por exemplo, “2030-04-01T12:00:00Z”)

Estratégia de fragmentação
Supondo que você decida usar 10 fragmentos, os números de fragmentos podem variar de 0 a 9. Ao registrar uma atividade, você calcularia o número do fragmento (por exemplo, usando uma função hash no ID do usuário e, depois, pegando o módulo do número de fragmentos) e o adicionaria como prefixo à chave de partição do GSI. Esse método distribui as entradas em diferentes fragmentos, mitigando o risco de partições sobrecarregadas.
Consultar o GSI fragmentado
Consultar itens dentro de determinado intervalo de tempo em todos os fragmentos em uma tabela do DynamoDB, na qual os dados são fragmentados em várias chaves de partição, requer uma abordagem diferente da consulta de uma única partição. Como as consultas do DynamoDB estão limitadas a uma única chave de partição por vez, não é possível consultar diretamente vários fragmentos com uma única operação de consulta. No entanto, você pode obter o resultado desejado por meio da lógica no nível da aplicação executando várias consultas, cada uma visando um fragmento específico e, depois, agregando os resultados. O procedimento a seguir explica como fazer isso.
Como consultar e agregar fragmentos
Identifique o intervalo de números de fragmentos usado na estratégia de fragmentação. Por exemplo, se você tiver 10 fragmentos, os números de fragmentos variarão de 0 a 9.
Para cada fragmento, crie e execute uma consulta para buscar itens dentro do intervalo de tempo desejado. Essas consultas podem ser executadas em paralelo para melhorar a eficiência. Use a chave de partição com o número do fragmento e a chave de classificação com o intervalo de tempo para essas consultas. Aqui está um exemplo de consulta para um único fragmento:
aws dynamodb query \ --table-name "YourTableName" \ --index-name "YourIndexName" \ --key-condition-expression "PK_GSI = :pk_val AND SK_GSI BETWEEN :start_date AND :end_date" \ --expression-attribute-values '{ ":pk_val": {"S": "ShardNumber#0"}, ":start_date": {"S": "2024-04-01"}, ":end_date": {"S": "2024-04-30"} }'
Você replicaria essa consulta para cada fragmento, ajustando a chave de partição adequadamente (por exemplo, “ShardNumber#1”, “ShardNumber#2”, …, “ShardNumber#9”).
Agregue os resultados de cada consulta após a conclusão de todas elas. Execute essa agregação no código da aplicação, combinando os resultados em um único conjunto de dados que representa os itens de todos os fragmentos dentro do intervalo de tempo especificado.
Considerações sobre a execução de consultas em paralelo
Cada consulta consome a capacidade de leitura da tabela ou do índice. Se você estiver usando throughput provisionado, a tabela deverá ser provisionada com capacidade suficiente para lidar com o pico de consultas paralelas. Se você estiver usando capacidade sob demanda, atente-se às possíveis implicações de custo.
Exemplo de código
Para executar consultas paralelas entre fragmentos no DynamoDB usando Python, é possível usar a biblioteca boto3, que é o SDK da Amazon Web Services para Python. Esse exemplo pressupõe que você tenha o boto3 instalado e configurado com as credenciais da AWS apropriadas.
O código Python a seguir demonstra como realizar consultas paralelas em vários fragmentos para determinado intervalo de tempo. Ele usa concurrent futures para executar consultas em paralelo, reduzindo o tempo geral de execução em comparação com a execução sequencial.
import boto3
from concurrent.futures import ThreadPoolExecutor, as_completed
# Initialize a DynamoDB client
dynamodb = boto3.client('dynamodb')
# Define your table name and the total number of shards
table_name = 'YourTableName'
total_shards = 10 # Example: 10 shards numbered 0 to 9
time_start = "2030-03-15T09:00:00Z"
time_end = "2030-03-15T10:00:00Z"
def query_shard(shard_number):
"""
Query items in a specific shard for the given time range.
"""
response = dynamodb.query(
TableName=table_name,
IndexName='YourGSIName', # Replace with your GSI name
KeyConditionExpression="PK_GSI = :pk_val AND SK_GSI BETWEEN :date_start AND :date_end",
ExpressionAttributeValues={
":pk_val": {"S": f"ShardNumber#{shard_number}"},
":date_start": {"S": time_start},
":date_end": {"S": time_end},
}
)
return response['Items']
# Use ThreadPoolExecutor to query across shards in parallel
with ThreadPoolExecutor(max_workers=total_shards) as executor:
# Submit a future for each shard query
futures = {executor.submit(query_shard, shard_number): shard_number for shard_number in range(total_shards)}
# Collect and aggregate results from all shards
all_items = []
for future in as_completed(futures):
shard_number = futures[future]
try:
shard_items = future.result()
all_items.extend(shard_items)
print(f"Shard {shard_number} returned {len(shard_items)} items")
except Exception as exc:
print(f"Shard {shard_number} generated an exception: {exc}")
# Process the aggregated results (e.g., sorting, filtering) as needed
# For example, simply printing the count of all retrieved items
print(f"Total items retrieved from all shards: {len(all_items)}")
Antes de executar esse código, substitua YourTableName
e YourGSIName
pelos nomes reais da tabela e do GSI da configuração do DynamoDB. Além disso, ajuste as variáveis total_shards
, time_start
e time_end
de acordo com seus requisitos específicos.
Esse script consulta cada fragmento em busca de itens dentro do intervalo de tempo especificado e agrega os resultados.