DynamoDB Query di Java (AWS SDK v2)

queryPaginator di AWS SDK for Java 2.x terlihat seperti koleksi padahal bukan. Ia adalah iterable malas yang bisa diulang, dan bedanya muncul di tagihan Anda saat kedua kalinya Anda melakukan loop atasnya. Untuk menentukan apakah Query memang pembacaan yang tepat, lihat Query vs. Scan.

Kode

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 menjalankan ulang query-nya setiap kali Anda mengiterasi

Terhadap fixture 600 lagu, tiap lagu ~3,9 KB dan semuanya di bawah Artist = "Arturo Sandoval", ddb.queryPaginator(request) kembali dalam 2,6 ms dan tidak mengirim apa pun. Lalu objek QueryIterable yang sama di-loop dua kali:

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 object

Dua loop for atas satu variabel, 569 read unit. Halamannya tidak pernah di-cache; setiap iterasi menyusuri LastEvaluatedKey dari awal lagi. Kalau Anda butuh item-nya dua kali, tuang iterable itu ke sebuah List sekali saja, seperti yang dilakukan contoh ini.

Sisi lain dari kemalasan yang sama adalah tempat error muncul. Bangun request yang key condition-nya menghilangkan partition key dan queryPaginator menerimanya tanpa protes, karena belum ada panggilan yang terjadi:

queryPaginator(bad) constructed without throwing
threw on iteration: DynamoDbException / ValidationException /
Query condition missed key schema element / http 400

Try-catch yang membungkus builder tidak menangkap apa pun. Ia harus membungkus loop-nya, dan itulah sebabnya contoh ini menaruh seluruh blok di dalam satu try.

Diukur 2026-07-28 terhadap DynamoDB Local (amazon/dynamodb-local) dengan software.amazon.awssdk:dynamodb 2.49.4 pada OpenJDK 26.0.1.

Penjelasan

  • ddb.queryPaginator(request).items() meratakan halaman-halamannya menjadi Iterable<Map<String, AttributeValue>> dan mempaginasi di belakang Anda, jadi loop dua tingkat pada contoh menciut jadi satu ketika Anda hanya menginginkan item-nya. Ia juga sebuah SdkIterable, jadi .stream() berfungsi.
  • Angka bertipe String di builder. AttributeValue.builder().n("1994") bukan salah ketik untuk .n(1994) — setter n() menerima java.lang.String, karena DynamoDB mengangkut angka sebagai teks desimal untuk menghindari pembulatan float biner. Mengoper int Java tidak akan ter-compile.
  • keyConditionExpression menerima satu kesamaan pada partition key plus paling banyak satu kondisi sort key (=, <, <=, >, >=, BETWEEN, begins_with); .scanIndexForward(false) membalik urutannya dan .indexName("...") mengarahkannya ke secondary index.
  • Enhanced Client adalah ergonomi yang lain. software.amazon.awssdk.enhanced.dynamodb memetakan bean beranotasi alih-alih Map<String, AttributeValue>, dan query-nya mengembalikan PageIterable<T> dengan semantik iterasi-ulang malas yang sama seperti yang diukur di atas.

Lakukan secara visual

Baik #hashKey maupun #rangeKey dalam contoh ini adalah alias yang tidak dipaksakan kepada Anda: Artist maupun SongTitle tidak ada dalam daftar 573 reserved word milik AWS. Pemeriksa reserved word memberi tahu nama atribut mana yang benar-benar butuh perlakuan #, sehingga peta alias berhenti menjadi kebiasaan tanpa alasan.

Untuk mencoba sebuah key condition terhadap tabel sungguhan sebelum Anda membangun QueryRequest, unduh DynoTable dan susuri hasilnya dalam sebuah grid.

Contoh terkait

Referensi

Bangun request ini secara visual

Susun operasi ini di DynamoDB Query Builder gratis — key condition, filter, index, Limit, urutan sortir, dan loop paginasi — lalu salin kembali sebagai program SDK v3, CLI, atau boto3 yang bisa dijalankan.

Buka DynamoDB Query Builder

Bekerja dengan DynamoDB tanpa Console

Klien desktop DynamoDB yang cepat dan menjalankan SQL sungguhan yang tidak bisa dijalankan DynamoDB — JOINs, GROUP BY, agregasi — dengan editing visual dan agen AI pada kunci Bedrock milik Anda sendiri.

Uji coba gratis 30 hari, tanpa kartu kredit — lalu paket Free tanpa batas waktu.