Perintah dan Cakupan
Pewawancara memberikan tabel peristiwa (event table) yang menerima operasi tulis terus-menerus dan meminta Anda membuat fact table harian. Eksekusi pertama dapat memindai seluruh riwayat, tetapi eksekusi berikutnya hanya boleh memproses data yang berubah. Peristiwa bisa datang terlambat, diperbarui, atau terduplikasi, dan kolom model dapat berubah. Jelaskan batas filter, unique key, strategi inkremental, rencana backfill, dan pemulihan setelah kegagalan.
Asumsikan data warehouse mendukung SQL, target diagregasi berdasarkan date_day, dan setiap peristiwa memiliki event_at, updated_at, serta event_id yang stabil. Nyatakan asumsi-asumsi ini di awal. Tanpa kunci yang stabil, semantik pembaruan dan deduplikasi akan berubah.
Apa yang Dinilai oleh Pewawancara
Pewawancara ingin melihat apakah Anda dapat mengurangi pemindaian data tanpa mengorbankan kebenaran hasil. Jawaban mendasar menyebutkan is_incremental() dan filter timestamp. Jawaban yang kuat menjelaskan mengapa filter harus mencakup data yang datang terlambat, mengapa agregat membutuhkan unique_key yang cocok dengan tingkat granularitasnya (grain), dan kapan --full-refresh wajib digunakan.
Mereka juga menguji apakah Anda membedakan tiga risiko: kehilangan peristiwa yang datang terlambat, menulis baris duplikat pada granularitas bisnis, dan mencampurkan logika lama serta baru setelah transformasi historis berubah. Materi wawancara data engineering saat ini memperlakukan model inkremental, snapshot, dan grafik dependensi sebagai topik persiapan praktis; pertanyaan ini menggabungkan SQL, pemodelan data, dan tata kelola eksekusi (run governance).
Pertanyaan Klarifikasi Sebelum Menjawab
Apa tingkat granularitas bisnisnya?
Jika satu baris mewakili satu hari, date_day dapat menjadi unique key. Jika satu baris mewakili seorang pengguna dan satu hari, kuncinya harus berupa (user_id, date_day). Granularitas mengubah kondisi merge, pemeriksaan duplikat, dan biaya backfill.
Seberapa terlambat data bisa tiba?
Jika peristiwa biasanya tidak terlambat lebih dari dua hari, hitung ulang tiga hari terakhir. Jika tidak ada batas atas yang dapat dipastikan, jendela tetap tidaklah cukup; gunakan watermark, perbaikan partisi, atau rekonsiliasi penuh secara berkala. Jendela harus mencakup distribusi keterlambatan yang dapat diterima.
Kolom mana yang mewakili pembaruan dari hulu (upstream)?
event_at adalah waktu bisnis, sedangkan updated_at adalah waktu modifikasi terakhir. Memfilter hanya berdasarkan event_at akan melewatkan peristiwa lama yang dikoreksi belakangan. Utamakan updated_at yang tepercaya atau urutan perubahan dan pastikan sumber tidak memundurkan nilainya.
Bagaimana perubahan model atau kolom dirilis?
Menambahkan kolom, menghapus kolom, dan mengubah logika perhitungan membutuhkan penanganan yang berbeda. Konfirmasikan apakah on_schema_change dapat menyinkronkan struktur, apakah baris lama harus di-backfill, dan apakah full refresh dapat dijadwalkan.
Kerangka Jawaban 30 Detik
“Pertama-tama saya akan mengonfirmasi granularitas target dan batas keterlambatan. Eksekusi pertama membangun model dari seluruh riwayat. Eksekusi berikutnya menggunakan is_incremental() untuk memfilter berdasarkan updated_at dan melihat ke belakang sepanjang jendela keterlambatan. Target mendeklarasikan unique_key yang cocok dengan granularitasnya, sehingga hari-hari terakhir diperbarui alih-alih ditambahkan sebagai duplikat. Saya mendeduplikasi jendela berdasarkan versi peristiwa sebelum melakukan agregasi, lalu menulis dengan merge atau padanan warehouse-nya. Saya menguji jendela, kunci, dan perilaku perubahan skema. Jika perubahan logika membuat hasil historis tidak konsisten, saya menjalankan --full-refresh terkontrol dan membangun kembali model hilir (downstream) yang terpengaruh. Terakhir, saya memantau baris yang diproses, waktu pembaruan maksimum, kunci duplikat, dan perbedaan antara inkremental versus penuh.”
Pembahasan Mendalam Langkah demi Langkah
1. Tentukan garis dasar kebenaran full-refresh
Tulis kueri lengkap terlebih dahulu: baca semua peristiwa dan lakukan agregasi pada granularitas target. Itu adalah garis dasar kebenaran. Output inkremental harus dapat direkonsiliasi dengan perhitungan penuh pada rentang waktu yang sama. Melakukan optimasi sebelum menetapkan garis dasar ini membuat rekaman yang terlewat sulit dideteksi.
2. Pilih batas filter inkremental
Percabangan inkremental hanya berlaku ketika tabel target sudah ada, --full-refresh tidak ada, dan model dikonfigurasikan sebagai inkremental. Salah satu opsinya adalah mengurangi waktu pembaruan maksimum target dengan jendela keterlambatan:
{{
config(
materialized = 'incremental',
unique_key = ['date_day'],
incremental_strategy = 'merge'
)
}}
with source_events as (
select *
from {{ ref('app_events') }}
{% if is_incremental() %}
where updated_at >= (
select coalesce(max(updated_at), '1900-01-01') from {{ this }}
) - interval '3 day'
{% endif %}
)
select
cast(event_at as date) as date_day,
count(distinct event_id) as events,
max(updated_at) as max_updated_at
from source_events
group by 1Nilai tiga hari adalah asumsi wawancara, bukan konstanta universal. Pilih jendela berdasarkan keterlambatan, SLA, dan biaya komputasi ulang. Sesuaikan ekspresi tanggal dengan data warehouse.
3. Buat unique key cocok dengan granularitas model
Untuk tabel harian, date_day adalah kuncinya. Untuk tabel user-day, gunakan ['user_id', 'date_day']. Kolom kunci tidak boleh berisi nilai null, jika tidak, operasi merge dapat gagal mencocokkan dan membuat duplikat. Tanpa kunci, banyak adapter berperilaku sebagai append-only, sehingga menghitung ulang suatu jendela dapat menulis beberapa baris untuk satu granularitas.
4. Lakukan deduplikasi di dalam jendela sebelum agregasi
Pemutaran ulang (replay) atau pembaruan CDC dapat menghasilkan beberapa versi dari satu peristiwa. Urutkan berdasarkan event_id dan waktu pembaruan, pertahankan versi terbaru, lalu lakukan agregasi:
with ranked_events as (
select
*,
row_number() over (
partition by event_id
order by updated_at desc, ingest_seq desc
) as rn
from source_events
),
deduped_events as (
select * from ranked_events where rn = 1
)
select
cast(event_at as date) as date_day,
count(*) as events,
max(updated_at) as max_updated_at
from deduped_events
group by 1Gunakan ingest_seq hanya jika ini merupakan tie-breaker yang stabil untuk timestamp yang sama. Jika tidak, sebut aturan tie tersebut sebagai kontrak sumber yang belum terselesaikan. Deduplikasi harus mendahului agregasi, atau kedua versi dari satu peristiwa akan terhitung ganda.
5. Pilih merge, partition overwrite, atau append
merge cocok untuk semantik pembaruan-dan-penyisipan (update-and-insert) yang dikunci oleh suatu granularitas. Beban kerja komputasi ulang partisi dapat menggunakan insert_overwrite, yang mengandalkan partisi alih-alih kunci baris. Append murni lebih sederhana ketika peristiwa hulu tidak pernah berubah. Pilihlah berdasarkan semantik pembaruan, biaya pemindaian, dan dukungan adapter daripada memperlakukan satu strategi sebagai strategi universal.
6. Tangani perubahan skema dan logika
Menambahkan kolom tidak serta merta mem-backfill baris lama; kolom yang dihapus dan perubahan tipe data mungkin baru muncul saat run time. on_schema_change dapat bernilai ignore, fail, append_new_columns, atau sync_all_columns, tetapi ini hanya melacak kolom tingkat atas dan tidak menggantikan backfill historis. Jika logika perhitungan berubah, riwayat lama dan baru mungkin mengikuti aturan yang berbeda, jadi jalankan --full-refresh dan bangun kembali model inkremental hilir yang terpengaruh.
7. Rancang backfill dan pemulihan kegagalan
Catat jendela keterlambatan, waktu pembaruan maksimum target, dan watermark sumber dalam metadata eksekusi. Setelah eksekusi jendela gagal, hitung ulang dari watermark target terakhir yang telah di-commit; jangan menganggap nilai "processed through" di memori sebagai kebenaran mutlak. Untuk perbaikan skala besar, proses partisi tanggal dengan konkurensi terbatas, lalu rekonsiliasi sampel terhadap kueri penuh agar satu kali refresh tidak membebani data warehouse.
8. Tutup siklus verifikasi
Verifikasi setidaknya empat sinyal: setiap event_id muncul paling banyak satu kali di dalam jendela; kunci target bersifat unik; output inkremental terkini berada dalam batas perbedaan yang diizinkan dari komputasi ulang penuh; serta baris yang diproses dan updated_at maksimum tidak melonjak secara tak terduga. Uji input kosong, peristiwa duplikat, pembaruan pada peristiwa lama, kedatangan terlambat, timestamp yang sama persis dengan batas, dan eksekusi inkremental setelah full refresh.
Contoh Jawaban Berkualitas Tinggi
“Pertama-tama saya akan mengonfirmasi granularitas model, batas keterlambatan, dan kolom pembaruan sumber. Asumsikan target memiliki satu baris per hari dan peristiwa memiliki event_id serta updated_at yang stabil. Eksekusi pertama dibangun dari riwayat; eksekusi berikutnya menggunakan is_incremental() dan melihat ke belakang tiga hari dari waktu pembaruan maksimum target. Jendela tersebut diturunkan dari keterlambatan, bukan dari aturan baku yang kaku.
Di dalam jendela tersebut, saya melakukan deduplikasi berdasarkan ID peristiwa dan versi, kemudian melakukan agregasi per hari. Target mendeklarasikan date_day sebagai unique_key-nya dan menggunakan merge sehingga hari-hari terakhir digantikan alih-alih diduplikasi. Untuk granularitas user-day, saya akan menggunakan composite key. Memfilter hanya berdasarkan waktu peristiwa akan melewatkan koreksi belakangan pada peristiwa lama, jadi saya lebih memilih timestamp pembaruan yang andal atau urutan perubahan.
Saya akan memantau ukuran jendela, watermark, baris yang diproses, kunci duplikat, dan rekonsiliasi inkremental versus penuh. Pengaturan perubahan skema dapat menangani evolusi struktural, tetapi tidak mengisi nilai historis. Jika logika berubah atau riwayat perlu diperbaiki, saya akan menjalankan full refresh terkontrol atau backfill terpartisi dan membangun kembali model hilir yang terpengaruh. Saya akan menguji input kosong, peristiwa terlambat dan duplikat, timestamp batas, serta perilaku percobaan ulang (retry) sebelum menyatakan model tersebut andal.”
Kesalahan Umum
Memfilter hanya berdasarkan event_at → pembaruan lama terlewatkan → gunakan updated_at atau watermark CDC eksplisit
Waktu bisnis tidak berubah ketika peristiwa lama dikoreksi. Jika pembaruan diizinkan, filter berdasarkan waktu pembaruan atau urutan perubahan dan verifikasi kontraknya.
Melakukan merge tanpa kunci → baris tidak dapat dicocokkan secara andal → tentukan granularitas dan kunci non-null terlebih dahulu
Sebuah kunci harus mengidentifikasi tepat satu baris target. Jika granularitasnya adalah user-day, hanya menggunakan tanggal akan menggabungkan pengguna yang berbeda ke dalam satu baris.
Mengasumsikan kolom baru di-backfill secara otomatis → nilai historis tetap kosong → rencanakan backfill atau full refresh
Sinkronisasi skema dan pengisian data historis adalah dua hal yang terpisah. Perubahan struktural mungkin ringan, tetapi baris lama yang terisi memerlukan pembaruan eksplisit atau pembuatan ulang.
Memilih jendela satu jam yang tetap → data yang datang terlambat berada di luar jendela → kalibrasikan dengan persentil dan rekonsiliasi
Pilih jendela berdasarkan distribusi keterlambatan, SLA, dan biaya. Pantau kedatangan data di luar jendela dan perluas atau perbaiki ketika distribusinya berubah.
Pertanyaan Lanjutan dan Tanggapan
Jika 5% peristiwa tiba dua hari terlambat, bagaimana Anda memilih jendela tersebut?
Pertama, konfirmasikan toleransi keterlambatan kesegaran data (freshness delay). Jika laporan harian boleh dikoreksi pada hari berikutnya, cakup dua hingga tiga hari dan rekonsiliasikan peristiwa yang terlambat. Jika hasil hari pertama harus stabil, gunakan watermark ditambah antrean perbaikan daripada hanya memperbesar jendela SQL. Validasi pilihan tersebut terhadap kurva keterlambatan dan biaya alih-alih sekadar menyalin persentasenya.
Apa yang terjadi jika unique_key terduplikasi di sumber?
Kunci duplikat pada input inkremental atau target dapat membuat adapter gagal atau menghasilkan output yang tidak terdefinisi. Periksa keunikan di kedua tempat, identifikasi sumber duplikat, lakukan deduplikasi berdasarkan versi peristiwa, atau definisikan ulang composite key yang mewakili granularitas sebenarnya. ID acak tidak boleh menyembunyikan business key yang tidak stabil.
SQL model berubah, tetapi Anda hanya ingin menghitung ulang tujuh hari. Bisakah Anda tetap menjalankannya secara inkremental?
Hanya jika hasil historis tidak terpengaruh oleh logika baru. Jika perubahan memengaruhi seluruh riwayat, eksekusi inkremental tujuh hari akan membuat tabel dengan aturan yang bercampur. Jalankan full refresh terkontrol atau komputasi ulang terpartisi untuk rentang yang terpengaruh dan bangun kembali model hilir.
Tabel hulu di-truncate. Bagaimana model inkremental memulihkan diri?
Hentikan pemajuan watermark, konfirmasikan pembangunan ulang sumber, dan putar ulang dari snapshot atau titik CDC yang andal. Jika sumber tidak lagi mencakup riwayat yang diperlukan, eksekusi inkremental akan memperlakukan sumber yang tidak lengkap sebagai garis dasar yang lengkap; pulihkan snapshot atau bangun ulang target secara penuh.