← Master Index
Vol. 04 Module 4.1 Lecture

ETL (Extract, Transform, Load)

Data Preparation

How This Lesson Fits the Module

You have collected raw data, cleaned tables, assigned labels, and created annotations. ETL (Extract, Transform, Load) wires those steps into repeatable pipelines: scheduled jobs, idempotent stages, and curated outputs that trainers and feature stores consume.

Notebook cells are prototypes; ETL is how AI engineering teams ship data daily without manual copy-paste. This lecture connects Module 4.1 topics to the orchestration mindset you will extend in later Volume 04 modules.

Learning Objectives

By the end of this lesson, students should be able to:

  • Define extract, transform, and load stages in an ML data pipeline.
  • Sketch a DAG from raw landing zone to training-ready Parquet.
  • Compare batch ETL vs streaming ingestion trade-offs.
  • Implement a small Python ETL script with logging and checkpoints.
  • Apply idempotency and partition strategies for backfills.
  • Hand off curated tables to Feature Engineering.

Introduction: Pipelines, Not One-Off Scripts

Extract pulls data from sources (APIs, DBs, files). Transform applies cleaning, joins, labeling merges, and business rules. Load writes curated datasets to the warehouse, object store, or feature store. In ML systems, transform often includes train/val/test splits and leakage checks from Data Leakage.

Definition — ETL vs ELT

ETL transforms before load into the destination (classic data warehouse). ELT loads raw into the warehouse first, then transforms with SQL (common in Snowflake/BigQuery). ML teams use both: raw landing (ELT-friendly) plus Python transforms for complex NLP/vision logic.

Reference Architecture

ZoneContentsMutability
RawAPI dumps, CSV snapshots, annotation exportsAppend-only
StagingParsed, typed, deduped tablesOverwrite per batch ID
CuratedJoined features + labels, splitsVersioned (v1, v2)
ServingFeature store, inference vectorsPoint-in-time correct
Module 4.1 Recap Extract ← Collection · Transform ← Cleaning, Labeling, Annotation · Load → curated files for modeling.

Batch vs Streaming

Batch ETL

  • Hourly/daily cron, Airflow, Dagster, Prefect
  • Full recompute or partition backfills
  • Best for training sets and reporting
  • Simpler correctness debugging

Streaming / Micro-batch

  • Kafka, Flink, Spark Structured Streaming
  • Low-latency features and online metrics
  • Complexity: late events, watermarks
  • Often paired with batch reconciliation

Most model training still uses batch curated tables; streaming feeds online features and monitoring. Volume 03 async I/O helps high-concurrency extract from APIs inside batch workers.

A Minimal Python ETL Job

"""ETL: raw events + labels -> curated training table"""
from pathlib import Path
import logging
import pandas as pd

logging.basicConfig(level=logging.INFO)
log = logging.getLogger("etl.train_table")

RAW_EVENTS = Path("data/raw/events")
RAW_LABELS = Path("data/labels")
CURATED = Path("data/curated")
CURATED.mkdir(parents=True, exist_ok=True)

def extract(batch_date: str) -> tuple[pd.DataFrame, pd.DataFrame]:
    events = pd.read_parquet(RAW_EVENTS / f"dt={batch_date}")
    labels = pd.read_csv(RAW_LABELS / f"labels_{batch_date}.csv")
    log.info("extracted events=%s labels=%s", len(events), len(labels))
    return events, labels

def transform(events: pd.DataFrame, labels: pd.DataFrame) -> pd.DataFrame:
    events = events.drop_duplicates(subset=["event_id"], keep="last")
    events["event_ts"] = pd.to_datetime(events["event_ts"], utc=True)
    df = events.merge(labels[["event_id", "label", "guideline_version"]], on="event_id", how="inner")
    df = df.loc[df["label"].notna()]
    return df

def load(df: pd.DataFrame, batch_date: str) -> Path:
    out = CURATED / f"train_table/dt={batch_date}" / "data.parquet"
    out.parent.mkdir(parents=True, exist_ok=True)
    df.to_parquet(out, index=False)
    log.info("loaded rows=%s path=%s", len(df), out)
    return out

def run(batch_date: str) -> Path:
    events, labels = extract(batch_date)
    curated = transform(events, labels)
    return load(curated, batch_date)

if __name__ == "__main__":
    run("2026-07-13")

Idempotency and Partitions

Re-running the same batch date should produce the same output path without duplicating rows in downstream consumers. Partition by dt=YYYY-MM-DD or batch_id so backfills replace one folder, not the entire dataset.

# Idempotent load — overwrite partition directory
partition = CURATED / "train_table" / "dt=2026-07-13"
if partition.exists():
    for f in partition.glob("*.parquet"):
        f.unlink()
df.to_parquet(partition / "data.parquet", index=False)
Definition — DAG (Directed Acyclic Graph)

A DAG lists pipeline tasks and dependencies: extract_eventsclean_eventsmerge_labelspublish_train_table. Orchestrators (Airflow, Dagster) schedule DAGs, retry failures, and alert on SLA misses.

Common Misconception: “ETL is only a data-engineer concern; ML engineers just read Parquet.”

Reality: ML engineers own transforms that affect labels, splits, and leakage. If you cannot rerun the pipeline, you cannot reproduce the model.

Common Misconception: “Streaming replaces batch ETL entirely for AI.”

Reality: Training usually needs point-in-time batch snapshots; streaming complements with fresh features and monitoring.

Quality Gates in Load

CheckFailure SignalAction
Row count vs prior day>50% dropBlock publish, page on-call
Label null rateSpike after mergeInspect label export version
Schema contractMissing columnFail CI on ETL script
Duplicate keysevent_id not uniqueFix transform dedupe

Knowledge Check

  1. Short Answer: What are the three ETL stages? Answer: Extract, Transform, Load.
  2. True/False: Raw zones should typically be append-only. Answer: True.
  3. Multiple Choice: Daily training table rebuild is mostly: (a) streaming, (b) batch ETL, (c) manual Excel, (d) GPU compile. Answer: (b).
  4. Short Answer: Why partition by date? Answer: Enables idempotent backfills and efficient incremental reads.
  5. True/False: ELT loads raw before transforming in-warehouse. Answer: True.
  6. Multiple Choice: DAG stands for: (a) Data API Graph, (b) Directed Acyclic Graph, (c) Dynamic Auto GPU, (d) Duplicate Annotation Guide. Answer: (b).
  7. Short Answer: One quality gate before publishing curated data? Answer: Row count sanity check, schema validation, or duplicate key check.
  8. True/False: Transform step is where cleaning and label merges belong. Answer: True.
  9. Multiple Choice: After ETL, next Module 4.1 topic: (a) Feature Engineering, (b) HTML basics, (c) git init, (d) tuple unpacking. Answer: (a).
  10. Short Answer: What does idempotent batch rerun mean? Answer: Same input batch produces the same output without duplicate side effects.

Key Takeaways

  • ETL turns Module 4.1 steps into scheduled, testable pipelines.
  • Separate raw, staging, and curated zones with clear mutability rules.
  • Batch jobs train models; streaming feeds latency-sensitive paths.
  • Partition and idempotency make backfills safe.
  • Next: Feature Engineering to build model inputs from curated tables.
Trainer’s Guide

Capstone wiring: Students chain collection → cleaning → label merge into one run(batch_date) script with logs and a row-count assertion.

Architecture whiteboard: Draw batch DAG vs streaming sidecar; discuss which steps must be identical at training and serving time.

What’s Next Curated tables feed Feature Engineering—where columns become model-ready signals.