Setiap tengah malam, sistem POS toko online mengekspor seluruh transaksi hari itu sebagai satu file CSV ke folder ekspor. Sepanjang hari tidak ada data yang dipindahkan — data menumpuk sebagai kumpulan file, lalu diolah sekaligus pada malam hari. Pola pengolahan sekaligus inilah yang disebut batch ingestion: cara kerja ingestion paling tua, paling sederhana, dan sampai hari ini paling banyak dipakai. Kita akan membedah pola jadwal dan jendela waktunya, menimbang trade-off-nya, lalu membangun implementasi mini yang menggabungkan CSV transaksi harian.

Pola Batch: Jadwal dan Jendela Waktu #

Batch ingestion memproses data dalam kelompok besar pada waktu yang terjadwal. Dua istilah kuncinya perlu dipisahkan. Jadwal menentukan kapan sebuah run dimulai — misalnya pukul 00:30 setiap hari lewat cron atau orchestrator seperti Airflow. Jendela waktu menentukan rentang data yang dibaca oleh run tersebut — misalnya “hanya transaksi tanggal 3 Oktober”. Run yang dimulai 00:30 dengan jendela “tanggal kemarin” bersifat deterministik: data apapun keadaan database-nya, jendela yang sama selalu menghasilkan kumpulan data yang sama.

Kombinasi keduanya menjadikan batch mudah diuji dan diperbaiki. Ketika laporan harian menampilkan angka yang salah, kita bisa menjalankan ulang run untuk jendela waktu tertentu tanpa menyentuh jendela lain. Kemampuan menjalankan ulang per jendela inilah yang membuat batch bertahan di era streaming.

Jadwal juga menentukan seberapa segar data analitik. Run per jam memberi data berumur paling lama satu jam dengan biaya 24 run per hari; run per hari memberi data berumur paling lama 24 jam dengan satu run saja. Memilih frekuensi adalah keputusan bisnis: laporan penjualan mingguan tidak membutuhkan run per jam, sedangkan dasbor yang dipantau tim operasional setiap pagi terasa basi bila datanya masih dari dua hari lalu.

Trade-off Batch #

Kekuatan batch dibayar dengan keterlambatan data. Perbandingan berikut menempatkan batch di samping streaming agar trade-off-nya terlihat jelas:

AspekBatchStreaming
Latensi dataJam hingga hariDetik hingga menit
KompleksitasRendah: skrip biasa + jadwalTinggi: sistem berjalan tanpa henti
Sumber dayaDipakai besar saat run sajaSelalu aktif sepanjang waktu
Menjalankan ulangMudah per jendela waktuPerlu replay event
Contoh kecocokanLaporan penjualan harianDeteksi penipuan real-time

Implementasi Mini: Menggabungkan CSV Harian #

Kita praktekkan pola batch paling sederhana: membaca seluruh file transaksi harian di folder landing/, menggabungkannya, lalu menulis satu file output untuk tim analitik. Contoh isinya:

text
id,pelanggan,total
1,Budi Santoso,150000
2,Siti Rahma,275000
3,Dewi Lestari,98000

Folder landing/ berisi tiga file sejenis: transaksi_2026-10-01.csv, transaksi_2026-10-02.csv, dan transaksi_2026-10-03.csv. Skrip berikut menggabungkan ketiganya:

python
import csv
from pathlib import Path

FOLDER_LANDING = Path("landing")
FOLDER_OUTPUT = Path("output")


def gabungkan_csv_harian():
    baris_gabungan = []
    for berkas in sorted(FOLDER_LANDING.glob("transaksi_*.csv")):
        with berkas.open(newline="") as f:
            pembaca = csv.DictReader(f)
            jumlah = 0
            for baris in pembaca:
                baris["sumber"] = berkas.name
                baris_gabungan.append(baris)
                jumlah += 1
        print(f"{berkas.name}: {jumlah} baris")
    return baris_gabungan


def tulis_output(baris_gabungan):
    FOLDER_OUTPUT.mkdir(exist_ok=True)
    tujuan = FOLDER_OUTPUT / "transaksi_gabungan.csv"
    kolom = list(baris_gabungan[0].keys())
    with tujuan.open("w", newline="") as f:
        penulis = csv.DictWriter(f, fieldnames=kolom)
        penulis.writeheader()
        penulis.writerows(baris_gabungan)
    return tujuan


baris = gabungkan_csv_harian()
tujuan = tulis_output(baris)
print(f"Total gabungan: {len(baris)} baris -> {tujuan}")

Output yang Dihasilkan:

text
transaksi_2026-10-01.csv: 3 baris
transaksi_2026-10-02.csv: 2 baris
transaksi_2026-10-03.csv: 4 baris
Total gabungan: 9 baris -> output/transaksi_gabungan.csv

Mari kita telaah baris-baris kode di atas:

  1. Baris 4-5 (FOLDER_LANDING dan FOLDER_OUTPUT): kedua lokasi folder didefinisikan sebagai konstanta di bagian atas sehingga mudah diganti saat dipindah ke server produksi.
  2. Baris 10 (sorted(...glob(...))): pola transaksi_*.csv hanya menangkap file transaksi, dan sorted() menjamin urutan pemrosesan dari tanggal terlama — urutan yang sama setiap run.
  3. Baris 12 (csv.DictReader): pembaca ini memakai baris pertama file sebagai nama kolom, sehingga setiap baris berupa dictionary {"id": ..., "pelanggan": ..., "total": ...}.
  4. Baris 15-16 (baris["sumber"] = berkas.name): setiap baris diberi kolom asal baru sebelum ditampung — jejak sederhana yang disebut lineage, memudahkan penelusuran saat satu angka di laporan dipertanyakan.
  5. Baris 25 (kolom = list(...keys())): daftar kolom diambil dari baris pertama yang sudah bertambah kolom sumber, sehingga penulis CSV tidak perlu menulis nama kolom dua kali.
  6. Baris 27-29 (DictWriter): penulis menulis header sekali lewat writeheader(), lalu seluruh baris lewat writerows().

File output/transaksi_gabungan.csv akhirnya berisi 9 baris dengan kolom id, pelanggan, total, sumber — siap dimuat ke staging. Detail modul csv dan pathlib bisa dipelajari di dokumentasi csv dan dokumentasi pathlib .

Skrip kita membaca seluruh file di landing/ pada setiap run. Selama folder hanya berisi file hari ini, pola ini efisien — tetapi begitu sumbernya berupa tabel berisi jutaan baris histori, menyalin semuanya setiap hari menjadi pemborosan yang nyata. Chapter Incremental Ingestion memperkenalkan teknik mengambil hanya data baru.