DynamoDB Batch Write di Python (boto3 batch_writer)

batch_writer() adalah satu-satunya panggilan DynamoDB yang di Python justru lebih ringan daripada di SDK lain. Ia menyangga put dan delete, memotongnya menjadi request BatchWriteItem berisi 25, dan mengirim ulang sendiri item yang belum diproses. Yang tidak ia lakukan adalah melindungi Anda dari dua kegagalan yang merusak sebagian besar bulk load, dan keduanya muncul saat flush, bukan pada baris yang menyuplai item bermasalah itu.

Kode

import boto3

dynamodb = boto3.resource("dynamodb")
table = dynamodb.Table("Music")

songs = [
    {"Artist": "Arturo Sandoval", "SongTitle": "Cubano Chant", "AlbumTitle": "Danzon", "Year": 1994},
    {"Artist": "Arturo Sandoval", "SongTitle": "A Mis Abuelos", "AlbumTitle": "Danzon", "Year": 1994},
    {"Artist": "Arturo Sandoval", "SongTitle": "Groovin' High", "AlbumTitle": "Swingin'", "Year": 1996},
]

with table.batch_writer() as batch:
    for song in songs:
        batch.put_item(Item=song)
    # batch_writer buffers deletes too — target a key you're NOT also putting
    # (two writes to the same key in one batch are rejected as a duplicate)
    batch.delete_item(Key={"Artist": "Ella Fitzgerald", "SongTitle": "Misty"})

print(f"Buffered {len(songs)} puts + 1 delete; the batch flushes on exit")

Penjelasan

  • Flush yang ditundabatch.put_item() menambahkan ke sebuah list. Tidak ada yang divalidasi, diserialisasi, atau dikirim sampai buffer mencapai 25 atau blok with berakhir, jadi traceback untuk item bermasalah datang dari flush, bukan dari panggilan put_item yang menyuplainya. Kalau Anda memuat dari sebuah iterator, simpan sendiri catatan apa saja yang masuk ke buffer.
  • Nilai Python biasa — ini API resource, jadi Anda menulis 1994, bukan {"N": "1994"}. Decimal wajib untuk apa pun yang pecahan; sebuah float diterima masuk ke buffer dan ditolak saat flush.
  • batch_writer() adalah method Table. Padanannya di sisi baca tidak: batch_get_item berada di ServiceResource, dan table.batch_get_item tidak ada. Sama sekali tidak ada helper buffering, pemotongan, atau percobaan ulang untuk pembacaan batch.
  • UnprocessedItems, bukan error — hanya itu percobaan ulang yang ia tangani. Tulis yang di-throttle dikirim ulang; sebuah ValidationException diteruskan. Lewat client.batch_write_item sebagai gantinya menyerahkan seluruh loop itu kepada Anda, seperti pada contoh Node.js.
  • Ia tidak bisa mengangkat batas layanan. 25 tulis per request, 400 KB per item, 16 MB per request, tanpa kondisi dan tanpa update, dan setiap put mengganti seluruh item yang tersimpan. Butuh pengaman, atau semua-atau-tidak-sama-sekali? TransactWriteItems.

Apa yang sebenarnya dilakukan batch_writer saat flush

Sangga 30 put dan perhatikan panggilan yang ia lakukan. Dengan membungkus table.meta.client.batch_write_item dan merekam ukuran request, terhadap DynamoDB Local 3.3.0:

batch sizes sent: [25, 5]

Dua request, dipotong tepat di batas layanan, dengan sisanya di-flush oleh __exit__. Flush itu tanpa syarat: lempar sebuah RuntimeError di dalam blok dan item yang tersangga tetap ditulis dalam perjalanan keluar. Bulk load yang mati di tengah jalan meninggalkan muatan separuh jadi, bukan meja bersih.

Sekarang dua kegagalan itu. Sangga key yang sama dua kali, yang terjadi begitu data sumber Anda punya duplikat:

with table.batch_writer() as batch:
    batch.put_item(Item={"Artist": "Dup", "SongTitle": "Key", "Year": 1})
    batch.put_item(Item={"Artist": "Dup", "SongTitle": "Key", "Year": 2})
botocore.exceptions.ClientError: An error occurred (ValidationException) when calling the
BatchWriteItem operation: Provided list of item keys contains duplicates

Tak satu pun put_item protes. batch_writer() tidak melakukan deduplikasi kecuali Anda memintanya, dan memintanya berarti table.batch_writer(overwrite_by_pkeys=["Artist", "SongTitle"]). Jalankan dua put yang sama lewat itu dan item tersimpan sebagai Year: 2 — buffer menyimpan tulis terakhir per key, jadi deduplikasi itu adalah kehilangan data secara diam-diam kalau dua baris Anda sebenarnya dimaksudkan sebagai item berbeda di bawah key yang keliru Anda tetapkan.

Yang kedua murni milik boto3 dan tidak pernah sampai ke DynamoDB:

TypeError: Float types are not supported. Use Decimal types instead.

Sebuah Rating bernilai 4.5 duduk di buffer tanpa keluhan lalu meledak saat flush. Decimal("4.5") bolak-balik dengan benar sebagai {"N": "4.5"}. Baca harga atau rating dari JSON dengan json.loads dan setiap angka menjadi float, jadi ini kegagalan pada percobaan pertama untuk sebagian besar skrip impor. Memberikan parse_float=Decimal ke json.loads memperbaikinya di sumbernya.

Kalau Anda berpindah antara nilai Python native dan format wire secara manual, konverter DynamoDB JSON menampilkan kedua sisi dari item yang sama sehingga Anda bisa melihat Decimal Anda sebenarnya menjadi apa.

Untuk melakukan bulk load dari CSV atau JSON tanpa menulis sendiri pemetaan tipenya, unduh DynoTable.

Contoh terkait

Referensi

Terakhir diverifikasi 2026-07-28 terhadap dokumentasi resmi AWS yang ditautkan di atas.

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.