Pemeriksa freshness pada chapter sebelumnya menyatakan partisi 19 Oktober sudah tiba — tetapi tidak menyatakan partisi tersebut utuh. Budi kemudian menemukan partisi itu hanya memuat 2.020 baris dari 4.040 yang dikirim sumber: batch kedua gagal tanpa jejak, dan dashboard keuangan kehilangan separuh transaksi. Data completeness mengukur jarak antara data yang diharapkan hadir dan data yang benar-benar termuat. Chapter ini membedah kelengkapan pada dua tingkat, melakukan rekonsiliasi angka diharapkan versus aktual per partisi, dan menunjukkan dari mana angka “diharapkan” yang tepercaya berasal.
Dua Tingkat Kelengkapan #
Kelengkapan bermasalah pada dua tingkat yang berbeda penanganannya:
| Tingkat | Pertanyaan | Contoh Pelanggaran |
|---|---|---|
| Sel (cell) | Apakah nilai yang wajib terisi memang terisi? | kolom pelanggan kosong pada 12 baris |
| Baris (record) | Apakah semua baris yang dikirim sumber sampai di tujuan? | partisi harian kehilangan separuh barisnya |
Kelengkapan tingkat sel sudah kita hitung pada chapter Dimensi Kualitas Data lewat persentase isna(). Tingkat baris justru yang lebih sering luput — tabel tetap terlihat sehat karena baris yang hilang tidak meninggalkan lubang; kolom terisi rapi, tipe data benar, dan nilai masuk akal. Yang tersisa tampak normal, dan itulah letak bahayanya: kekurangan baris tidak memunculkan galat apa pun di dalam data itu sendiri. Deteksinya menuntut pembanding eksternal — kita harus tahu berapa baris yang seharusnya ada sebelum bisa menyimpulkan ada yang hilang.
Rekonsiliasi: Diharapkan vs Aktual #
Rekonsiliasi kelengkapan membandingkan dua angka per partisi: jumlah baris diharapkan dari sumber (manifest, laporan upstream) dan jumlah baris aktual di warehouse. Rasio aktual / diharapkan menjadi skor kelengkapan, lalu dibandingkan dengan pita toleransi — misalnya 99% hingga 101% — karena jumlah baris yang sedikit bergeser masih wajar akibat late arriving data atau koreksi kecil. Rasio di luar pita membagi masalah menjadi dua vonis: HILANG bila nol baris termuat (partisi gagal total) dan PARSIAL bila sebagian termuat (batch tertentu gagal).
Memeriksa Kelengkapan Partisi Harian #
Skrip berikut merekonsiliasi enam partisi harian pesanan TokoKita. Angka diharapkan dibangkitkan dengan seed tetap sebagai tiruan manifest upstream; dua anomali disisipkan pada salinan warehouse:
"""Rekonsiliasi kelengkapan partisi harian: diharapkan (manifest) vs aktual (warehouse)."""
import random
from datetime import date, timedelta
rng = random.Random(42)
mulai = date(2026, 10, 15)
tanggal = [mulai + timedelta(days=i) for i in range(6)]
# Jumlah baris per partisi menurut manifest upstream.
diharapkan = {t.isoformat(): rng.randint(3900, 4300) for t in tanggal}
# Jumlah baris yang benar-benar termuat di warehouse.
aktual = dict(diharapkan)
aktual[tanggal[2].isoformat()] = 0 # partisi 17 Okt: load gagal total
aktual[tanggal[4].isoformat()] //= 2 # partisi 19 Okt: batch kedua gagal
TOLERANSI = (0.99, 1.01) # pita 99%-101% dianggap lengkap
print(f"{'partisi':12}{'diharapkan':>12}{'aktual':>8}{'kelengkapan':>13} status")
hilang, parsial = [], []
for t in sorted(diharapkan):
target, nyata = diharapkan[t], aktual[t]
rasio = nyata / target
if nyata == 0:
status = "HILANG"
hilang.append(t)
elif not (TOLERANSI[0] <= rasio <= TOLERANSI[1]):
status = "PARSIAL"
parsial.append(t)
else:
status = "OK"
print(f"{t:12}{target:>12}{nyata:>8}{rasio:>13.1%} {status}")
total_target = sum(diharapkan.values())
total_nyata = sum(aktual.values())
print(f"\ntotal baris : {total_nyata} dari {total_target} ({total_nyata / total_target:.1%})")
print(f"partisi hilang : {hilang}")
print(f"partisi parsial: {parsial}")Output yang Dihasilkan:
partisi diharapkan aktual kelengkapan status
2026-10-15 4227 4227 100.0% OK
2026-10-16 3957 3957 100.0% OK
2026-10-17 3912 0 0.0% HILANG
2026-10-18 4279 4279 100.0% OK
2026-10-19 4040 2020 50.0% PARSIAL
2026-10-20 4025 4025 100.0% OK
total baris : 18508 dari 24440 (75.7%)
partisi hilang : ['2026-10-17']
partisi parsial: ['2026-10-19']Mari kita telaah baris-baris kode di atas:
- Baris 10 (
diharapkan): kamus tanggal-ke-jumlah-baris ini berperan sebagai manifest — di produksi, angka ini dibaca dari berkas manifest yang ditulis proses ekstraksi, bukan dibangkitkan. - Baris 13-15 (
aktual): salinan warehouse mulai dari salinan manifest lalu dua anomali disisipkan; pola ini meniru kenyataan bahwa warehouse tidak tahu sendiri datanya kurang. - Baris 24-29 (vonis per partisi): kasus
nyata == 0diputuskan lebih dulu karena rasio 0% tetap valid secara matematika tetapi maknanya berbeda dari 50% — partisi hilang total menunjuk kegagalan load, bukan kegagalan batch. - Baris 34-36 (rekonsiliasi total): jumlah keseluruhan 75,7% menunjukkan bahwa tiga perempat data termuat — angka ini yang dilaporkan ke pemilik data sebagai dampak agregat.
- Baris 37-38 (daftar tindakan): dua daftar terakhir adalah tiket kerja:
2026-10-17perlu di-load ulang dari sumber,2026-10-19perlu ditelusuri batch mana yang gagal.
Perhatikan bahwa pemeriksa freshness pada chapter sebelumnya akan menyatakan tabel ini segar — partisi terbaru (20 Oktober) utuh dan baru tiba. Freshness dan completeness benar-benar dua dimensi independen: satu mengukur umur, satu mengukur jumlah, dan keduanya wajib diperiksa bersama sebelum data dinyatakan layak pakai.
Kombinasi keduanya juga pas menjadi klausul data contract: SLA freshness menjaga umur, aturan kelengkapan menjaga jumlah, dan keduanya dievaluasi di gerbang yang sama sebelum publikasi.
Dari Mana Angka Diharapkan Datang #
Rekonsiliasi hanya sekuat sumber ekspektasinya. Empat sumber yang lazim dipakai industri, diurutkan dari yang paling tegas:
- Manifest ekstraksi: proses ekstraksi menulis jumlah baris per partisi ke berkas manifest — kontrak eksplisit antara tahap ekstrak dan load.
- Watermark kontinuitas: bila sumber mendukung penanda urutan (offset Kafka,
updated_at), baris berikutnya harus melanjutkan watermark terakhir tanpa celah. - Baseline historis: median jumlah baris 30 hari terakhir menjadi ekspektasi statistis ketika manifest tidak tersedia.
- Hitung silang sistem: jumlah baris di sistem sumber dibandingkan langsung dengan jumlah di warehouse melalui query per partisi.
Praktik terbaiknya adalah memakai lebih dari satu sumber sekaligus: manifest sebagai ekspektasi utama, baseline historis sebagai penyangga ketika manifest terlambat ditulis. Dua sumber yang saling setuju memberi keyakinan; dua sumber yang berselisih sudah merupakan temuan tersendiri yang layak ditelusuri.
Pemeriksaan jumlah baris di tingkat tool juga sudah matang: Great Expectations menyediakan expectation jumlah baris tabel seperti expect_table_row_count_to_be_between yang bisa digabung ke dalam suite kontrak (dokumentasi di docs.greatexpectations.io
).
Jumlah baris yang cocok belum menutup pemeriksaan — dua tabel bisa sama-sama lengkap tetapi saling bertentangan angkanya. Kita bedah ketegangan antar tabel pada chapter berikutnya: Data Consistency.