DynamoDB Query in Java (AWS SDK v2)
queryPaginator nell'AWS SDK for Java 2.x sembra una collection e non lo è. È un iterabile pigro e ri-percorribile, e la differenza si vede sulla tua bolletta la seconda volta che ci fai un loop sopra. Per capire se Query è la lettura giusta, vedi Query vs Scan.
Codice
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import software.amazon.awssdk.regions.Region;
import software.amazon.awssdk.services.dynamodb.DynamoDbClient;
import software.amazon.awssdk.services.dynamodb.model.AttributeValue;
import software.amazon.awssdk.services.dynamodb.model.DynamoDbException;
import software.amazon.awssdk.services.dynamodb.model.QueryRequest;
import software.amazon.awssdk.services.dynamodb.model.QueryResponse;
public class QueryExample {
public static void main(String[] args) {
try (DynamoDbClient ddb = DynamoDbClient.builder()
.region(Region.US_EAST_1)
.build()) {
Map<String, String> names = new HashMap<>();
names.put("#hashKey", "Artist");
names.put("#rangeKey", "SongTitle");
Map<String, AttributeValue> values = new HashMap<>();
values.put(":hashKeyValue", AttributeValue.builder().s("Arturo Sandoval").build());
values.put(":rangeKeyValue", AttributeValue.builder().s("C").build());
QueryRequest request = QueryRequest.builder()
.tableName("Music")
.keyConditionExpression(
"#hashKey = :hashKeyValue AND begins_with(#rangeKey, :rangeKeyValue)")
.expressionAttributeNames(names)
.expressionAttributeValues(values)
.build();
List<Map<String, AttributeValue>> items = new ArrayList<>();
for (QueryResponse page : ddb.queryPaginator(request)) {
items.addAll(page.items());
}
System.out.println("Found " + items.size() + " items");
} catch (DynamoDbException e) {
System.err.println(e.getMessage());
}
}
}QueryIterable riesegue la query ogni volta che la iteri
Su una fixture di 600 canzoni, ognuna da ~3,9 KB e tutte sotto Artist = "Arturo Sandoval", ddb.queryPaginator(request) è tornato in 2,6 ms senza inviare nulla. Poi lo stesso oggetto QueryIterable è stato percorso due volte:
queryPaginator(request) returned in 2.60 ms (class QueryIterable, 0 requests)
iteration 1: pages=3 items=600 capacity=284.5
iteration 2: pages=3 items=600 capacity=284.5 <- same objectDue cicli for su una sola variabile, 569 unità di lettura. Le pagine non sono mai state messe in cache; ogni iterazione ripercorre LastEvaluatedKey da capo. Se ti servono gli Item due volte, svuota l'iterabile in una List una volta sola, come fa l'esempio.
Il rovescio della stessa pigrizia è dove emergono gli errori. Costruisci una richiesta la cui key condition omette la chiave di partizione e queryPaginator la accetta senza protestare, perché nessuna chiamata è ancora avvenuta:
queryPaginator(bad) constructed without throwing
threw on iteration: DynamoDbException / ValidationException /
Query condition missed key schema element / http 400Un try-catch avvolto attorno al builder non intercetta nulla. Deve avvolgere il loop, ed è per questo che l'esempio mette l'intero blocco dentro un solo try.
Misurato il 2026-07-28 su DynamoDB Local (amazon/dynamodb-local) con software.amazon.awssdk:dynamodb 2.49.4 su OpenJDK 26.0.1.
Spiegazione
ddb.queryPaginator(request).items()appiattisce le pagine in unIterable<Map<String, AttributeValue>>e pagina dietro le quinte, quindi il doppio loop dell'esempio si riduce a uno quando vuoi solo gli Item. È anche unSdkIterable, quindi.stream()funziona.- I numeri sono
Stringnel builder.AttributeValue.builder().n("1994")non è un refuso per.n(1994)— il settern()prende unajava.lang.String, perché DynamoDB trasporta i numeri come testo decimale per evitare l'arrotondamento binario dei float. Passare unintJava non compila. keyConditionExpressionprende un'uguaglianza sulla chiave di partizione più al massimo una condizione sulla chiave di ordinamento (=,<,<=,>,>=,BETWEEN,begins_with);.scanIndexForward(false)inverte l'ordine e.indexName("...")punta la query a un indice secondario.- L'Enhanced Client è l'altra ergonomia.
software.amazon.awssdk.enhanced.dynamodbmappa bean annotati invece diMap<String, AttributeValue>, e la suaqueryrestituisce unPageIterable<T>con la stessa semantica di ri-iterazione pigra misurata sopra.
Fallo visivamente
Sia #hashKey sia #rangeKey in questo esempio sono alias che nulla ti impone: né Artist né SongTitle sono nella lista AWS delle 573 parole riservate. Il controllo delle parole riservate ti dice quali dei tuoi nomi di attributo hanno davvero bisogno del trattamento con #, così la mappa degli alias smette di essere un rito.
Per provare una key condition su una tabella vera prima di costruire la QueryRequest, scarica DynoTable e sfoglia i risultati in una griglia.
Esempi correlati
- DynamoDB Query in Go — la stessa query con AWS SDK for Go v2.
- DynamoDB Scan in Java — quando non puoi entrare in una partizione tramite chiave.
- Query vs Scan — perché
Queryè il default giusto. - Key condition expressions — ogni operatore legale su chiave di partizione e di ordinamento.
- "Query condition missed key schema element" — la key condition nomina l'attributo sbagliato o salta la chiave di partizione.
- "Query key condition not supported" — un operatore che la key condition non può usare, come contains o una seconda condizione sulla chiave di ordinamento.