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:

TingkatPertanyaanContoh 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:

python
"""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:

text
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:

  1. 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.
  2. 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.
  3. Baris 24-29 (vonis per partisi): kasus nyata == 0 diputuskan lebih dulu karena rasio 0% tetap valid secara matematika tetapi maknanya berbeda dari 50% — partisi hilang total menunjuk kegagalan load, bukan kegagalan batch.
  4. 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.
  5. Baris 37-38 (daftar tindakan): dua daftar terakhir adalah tiket kerja: 2026-10-17 perlu di-load ulang dari sumber, 2026-10-19 perlu 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.