Membangun fondasi data sistem ML: pipeline ingestion dari berbagai sumber, processing batch dan streaming, workflow orchestration, serta feature store yang menjamin training dan serving memakai nilai feature yang sama

Setelah di episode 16 model kalian menjawab dari basis pengetahuan, sekarang kita mundur satu lapisan ke bagian yang paling tidak glamor tapi paling menentukan: data pipeline. Semua yang sudah kalian bangun — feature, training, monitoring — bergantung pada satu pertanyaan: apakah data yang masuk ke sistem benar, segar, dan konsisten?
MLE sering menemukan dirinya di persimpangan: model bagus, tapi data pipeline berantakan sehingga training selalu pakai data telat atau bermasalah. Episode ini membangun pipeline yang solid: cara menyerap data dari berbagai sumber, memprosesnya secara batch maupun streaming, mengatur orkestrasi, dan — yang paling penting untuk MLE — feature store yang menyatukan feature untuk training dan serving.
Data datang dari banyak tempat: database transaksional (PostgreSQL), log aplikasi (Kafka), file (S3), API eksternal. Pipeline ingestion menggerakkan data ke tempat yang bisa diproses:
| Sumber | Teknik | Karakteristik |
|---|---|---|
| Database (CDC) | Debezium, Kafka Connect | Perubahan baris direplikasi real-time |
| Log / event | Kafka, Kinesis, Pub/Sub | Streaming volume besar |
| File batch | Airflow/Prefect ke object storage | Terjadwal, mudah dipahami |
| API eksternal | Polling terjadwal | Rate limit, retry wajib |
Prinsip yang wajib: data mentah bersifat immutabel (sudah kita bahas di episode 8). Pipeline ingestion menyimpan raw ke object storage (S3/GCS) sebagai source of truth, dan semua proses turunan membaca dari sana — bukan mengubahnya.
Dua mode pemrosesan dengan trade-off latency vs kompleksitas:
| Mode | Latency | Kapan dipakai | Tools |
|---|---|---|---|
| Batch | Menit-jam | Analisis historis, retraining, laporan | Spark, DuckDB, pandas |
| Streaming | Detik-menit | Real-time feature, alerting | Flink, Spark Streaming, Kafka Streams |
Prinsip yang mencegah kekacauan: jangan memproses streaming kalau batch sudah cukup. Streaming menambah biaya operasional besar; gunakan hanya saat data memang harus sampai dalam hitungan detik (misal fraud scoring real-time).
def build_training_dataset(period_start: str, period_end: str) -> pd.DataFrame:
raw = read_raw_events(period_start, period_end) # dari object storage
cleaned = clean(raw) # dedup, tipe data, missing
aggregated = aggregate_features(cleaned) # feature engineering
aggregated.to_parquet(f"datasets/events_{period_start}_{period_end}.parquet")
return aggregatedSaat pipeline punya banyak tahap dengan dependensi (ingest → clean → aggregate → train), kalian butuh orchestrator — bukan bash cron raksasa. Dua pilihan utama:
Konsep inti orkestrasi yang harus dipahami:
from prefect import flow, task
@task
def ingest():
...
@task
def clean(df):
...
@flow
def ml_data_pipeline():
raw = ingest()
df = clean(raw)
features = build_features(df)
features.to_parquet("datasets/train_latest.parquet")Ini bagian paling penting bagi MLE. Feature store adalah sistem terpusat yang menyimpan feature sehingga:
Tanpa feature store:
training → hitung feature sendiri (script A)
serving → hitung feature sendiri lagi (script B, berbeda!)
→ training-serving skew (masalah besar di episode 4)
Dengan feature store:
training ─┐
├──► Feature Store (definisi tunggal)
serving ─┘ │
├──► train model
└──► serve modelFitur kunci yang diharapkan dari feature store: definisi feature terpusat, point-in-time correctness (mengambil nilai feature "pada waktu yang benar" untuk tiap baris, menghindari data leakage dari masa depan), dan online serving dengan latency rendah.
Pilihan tooling: Feast (open source, self-hosted), Featureform, atau platform cloud (SageMaker Feature Store, Vertex AI Feature Store). Mulai dari konsep dulu — sering kali solusi sederhana (tabel terpusat + query time) sudah cukup sebelum menambah platform.
Pipeline tanpa checkpoint kualitas akan mengalirkan sampah ke training. Masukkan validasi otomatis di setiap tahap:
def validate(df: pd.DataFrame) -> None:
assert df.notna().mean().min() > 0.95, "missing rate terlalu tinggi"
assert df["event_count"].min() >= 0, "nilai negatif tidak valid"
schema = {"user_id": "int64", "event_count": "int64"}
assert df.dtypes.astype(str).to_dict() == schema, "schema berubah"Gabungkan dengan data validation tool seperti Great Expectations atau pandas-based assert. Pipeline yang meloloskan data bermasalah adalah hutang teknis yang dibayar berkali-kali di tahap model.
Important
Aturan yang menyelamatkan banyak tim: pipeline harus gagal dengan keras, bukan berjalan diam-diam dengan data rusak. Gagal cepat = alert cepat = debugging lebih murah. Pipeline yang "sukses" tapi outputnya salah adalah kegagalan yang paling berbahaya karena tidak ada yang tahu.
| Pitfall | Dampak | Pencegahan |
|---|---|---|
| Feature dihitung dua tempat (train vs serve) | Training-serving skew | Feature store / definisi tunggal |
| Pipeline tanpa idempotency | Duplikat data saat rerun | Idempotent job + dedup |
| Validasi data diabaikan | Data rusak sampai ke training | Gate kualitas di tiap tahap |
| Orchestrator = cron raksasa | Tidak terpantau, retry manual | Airflow/Prefect dengan observability |
| Streaming untuk hal yang cukup batch | Biaya ops membengkak | Pilih batch kecuali butuh real-time |
Pada episode 17 ini, kalian telah membangun fondasi data:
Di episode 18 selanjutnya kita akan membahas ML Security — adversarial robustness, prompt injection, dan data poisoning: ancaman yang menargetkan model, pipeline data, dan cara pertahanannya. Sampai jumpa di episode 18!