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 request | Round trip | Unit baca | Item dikembalikan |
|---|---|---|---|
| apa adanya | 3 | 284.5 | 8 |
.limit(25) | 25 | 288.0 | 8 |
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 400Year 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.
filterExpressionberjalan setelah pembacaan, jadi dua respons kosong itu ditagih penuh, danif (page.items().isEmpty()) breakapa pun akan melaporkan tabel kosong. ddb.scanPaginator(request).items()meratakan halaman-halaman menjadi satuIterable<Map<String, AttributeValue>>dan melakukan paginasi di belakang Anda, yang meringkas loop bersarang saat Anda hanya menginginkan item-nya. Ia sebuahSdkIterable, jadi.stream()bekerja —.items().stream().count()mengembalikan 8 di sini.ScanIterablemenjalankan 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 sebuahList, seperti pada contoh itu.- Angka bertipe
Stringdi builder-nya.AttributeValue.builder().n("2010")menerimajava.lang.String, karena DynamoDB mengangkut angka sebagai teks desimal. Melewatkaninttidak 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
- DynamoDB Scan di Go — scan yang sama dengan AWS SDK for Go v2.
- DynamoDB Query di Java — pembacaan yang lebih murah yang biasanya harus Anda pakai.
- Query vs. Scan — kapan (jarang) sebuah
Scanbisa dibenarkan. - Mengapa Scan DynamoDB saya lambat dan mahal? — model biayanya dan cara menghindarinya.
- DynamoDB ProvisionedThroughputExceededException — apa yang dilakukan scan seluruh tabel terhadap kapasitas tabel provisioned.
- DynamoDB ThrottlingException — throttle yang satunya, dan bagaimana exponential backoff menanganinya.
Referensi
- Scan — Amazon DynamoDB API Reference
- Use Scan with an AWS SDK or CLI — Amazon DynamoDB Developer Guide
- DynamoDbClient — AWS SDK for Java 2.x API Reference
- ScanRequest — AWS SDK for Java 2.x API Reference
- Scanning tables — Amazon DynamoDB Developer Guide
- Reserved words in DynamoDB — Amazon DynamoDB Developer Guide