DynamoDB Scan di Java (AWS SDK v2)

scanPaginator mengurus LastEvaluatedKey untuk Anda, dan satu tombol yang paling sering dicari orang berikutnya — .limit(...) — membuat scan yang sama jadi lebih lambat dan sedikit lebih mahal. Untuk tahu kapan harus menghindari Scan sama sekali, 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.ScanRequest;
import software.amazon.awssdk.services.dynamodb.model.ScanResponse;

public class ScanExample {
    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("#filter0", "Year");

            Map<String, AttributeValue> values = new HashMap<>();
            values.put(":filterValue0", AttributeValue.builder().n("2010").build());

            ScanRequest request = ScanRequest.builder()
                    .tableName("Music")
                    .filterExpression("#filter0 >= :filterValue0")
                    .expressionAttributeNames(names)
                    .expressionAttributeValues(values)
                    .build();

            List<Map<String, AttributeValue>> items = new ArrayList<>();
            for (ScanResponse page : ddb.scanPaginator(request)) {
                items.addAll(page.items());
            }
            System.out.println("Matched " + items.size() + " items");
        } catch (DynamoDbException e) {
            System.err.println(e.getMessage());
        }
    }
}

.limit(25) mengubah 3 request menjadi 25 dan biayanya lebih mahal

Fixture-nya memuat 600 lagu berukuran sekitar 3,9 KB masing-masing, dan 8 di antaranya cocok. Jalankan contoh itu apa adanya, lalu jalankan lagi dengan .limit(25):

Bentuk requestRound tripUnit bacaItem dikembalikan
apa adanya3284.58
.limit(25)25288.08

Kapasitas ditagih per halaman, dibulatkan ke atas ke batas 4 KB, jadi mengiris satu pembacaan 1 MB menjadi 24 pembacaan kecil membayar pembulatan itu 24 kali. Request ke-25 adalah kejutan lainnya: halaman 24 menghabiskan tabelnya dan tetap mengembalikan sebuah LastEvaluatedKey, jadi paginator-nya bertanya sekali lagi dan mendapat scannedCount=0. DynamoDB memberi sinyal "tak ada data lagi" dengan menghilangkan key itu, bukan dengan mengembalikan halaman pendek, dan pada batas Limit ia memang belum tahu.

.limit(...) adalah tombol pemerata kapasitas untuk job latar belakang yang tak ingin Anda biarkan men-throttle tabel live. Ia bukan cara membuat scan jadi lebih murah atau lebih singkat.

Alias-nya bukan soal gaya

Hapus #filter0 lalu filter langsung pada Year, dan SDK memunculkannya lewat awsErrorDetails():

DynamoDbException / ValidationException /
Invalid FilterExpression: Attribute name is a reserved keyword; reserved keyword: Year
/ http 400

Year adalah salah satu dari 573 reserved word. Seperti setiap error paginator di SDK ini, ia datang pada iterasi pertama loop for, bukan saat Anda memanggil scanPaginator(request), jadi try-nya harus membungkus loop itu.

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

Penjelasan

  • Dua halaman pertama mengembalikan nol item. Dengan filter ini hasil per halamannya adalah 0, 0 dan 8, pada 128,5, 128,5 dan 27,5 unit baca. filterExpression berjalan setelah pembacaan, jadi dua respons kosong itu ditagih penuh, dan if (page.items().isEmpty()) break apa pun akan melaporkan tabel kosong.
  • ddb.scanPaginator(request).items() meratakan halaman-halaman menjadi satu Iterable<Map<String, AttributeValue>> dan melakukan paginasi di belakang Anda, yang meringkas loop bersarang saat Anda hanya menginginkan item-nya. Ia sebuah SdkIterable, jadi .stream() bekerja — .items().stream().count() mengembalikan 8 di sini.
  • ScanIterable menjalankan ulang scan-nya pada setiap iterasi. Ia lazy, bukan ter-cache: melakukan loop atas objek yang sama dua kali mengirim request-nya dua kali dan menagih dua kali. Kuras sekali ke sebuah List, seperti pada contoh itu.
  • Angka bertipe String di builder-nya. AttributeValue.builder().n("2010") menerima java.lang.String, karena DynamoDB mengangkut angka sebagai teks desimal. Melewatkan int tidak akan terkompilasi.
  • .segment(...) / .totalSegments(...) memecah scan seluruh tabel ke beberapa worker, masing-masing dengan paginator-nya sendiri. Itu membagi waktu dinding dan menghabiskan kapasitas yang sama.

Lakukan secara visual

Pemeriksa reserved word menjalankan nama atribut Anda terhadap daftar AWS lengkap dan mengembalikan map ExpressionAttributeNames, yang lebih cepat daripada mempelajari bahwa Year, Name, Size dan Status semuanya sudah terpakai, satu ValidationException demi satu.

Untuk mencoba sebuah filter terhadap tabel sungguhan sebelum Anda merangkainya ke dalam sebuah ScanRequest, unduh DynoTable dan telusuri hasilnya halaman demi halaman 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.