skip to content

Olist Big Data Pipeline

[completed]github ↗
  • Apache Spark3.3.0
  • Apache Airflow2.10.5
  • dbt1.9.0
  • PostgreSQL
  • MinIO
  • Apache Superset4.0.2
  • Grafana11.1.0
  • Docker

Project Overview

The big-data case study of the Huawei Yapay Zeka Uzmanlık Programı (AI Expertise Program): take the Olist Brazilian e-commerce dataset — 9 CSV tables, 1,550,922 rows of real marketplace data — and grow it, over three assignment phases, into a production-style data platform that answers seven business questions every day without a human in the loop.

Medallion architecture: Airflow orchestrates Spark ingestion into MinIO bronze, a loader into Postgres raw, dbt into silver and gold, feeding Superset and Grafana

The final pipeline: Apache Spark ingests the CSVs as Parquet into a MinIO data lake (bronze, immutable), a pyarrow loader copies bronze into Postgres (raw), dbt builds the cleaned silver and star-schema gold layers with 46 schema tests as quality gates, and Apache Airflow runs the whole DAG daily. Superset dashboards answer the business questions; Grafana watches the pipeline's health. End-to-end: ~1.8 minutes, verified idempotent with two consecutive fully green runs.

Data quality, measured — not assumed

The first real lesson of the project: data lies, so profile before you trust. Measured findings that shaped the silver layer:

  • 26.2% of the geolocation table is exact duplicates (261,831 of 1,000,163 rows) — any naive join through it inflates every downstream number. Deduplicated to 19,015 rows (one per ZIP prefix), enforced by a unique test forever.
  • 789 review keys attach to multiple orders; 547 orders have multiple reviews — the "latest review per order" rule is tested, not tribal knowledge.
  • 99,441 order-scoped customer ids hide 96,096 real people — "customer count" is wrong by 3,345 unless you know which id to count.
  • Referential integrity: zero violations. The dirt lives in content, not structure.

The star schema

Gold layer star schema: three fact tables at three grains, four shared dimensions

Every business question has the same shape — aggregate one measure, cut by one or two attributes — so gold is a star schema: three fact tables at three grains (order item, order, payment record) and four dimensions (customers, products, sellers, calendar), plus one thin, tested reporting view per question. The grain distinction is load-bearing: one order can mix credit card and voucher, which is exactly why payments get their own fact table.

Decisions I'd defend

  • ELT over ETL. Spark only moves and types data; every transformation lives in dbt inside the warehouse, where it is versioned, testable SQL. Bronze is immutable, so a bad rule means rebuilding from bronze — never re-extracting from source.
  • Tests as the pipeline's brake. The 46 dbt tests run inside dbt build in dependency order; during development a wrong deduplication rule tripped a unique test and stopped the build before any dashboard showed a wrong number. That single save justified the whole approach.
  • Task boundaries = failure domains. The Airflow DAG's four tasks pass no data to each other — each reads from the lake or warehouse — so any task can be re-run alone, and a transform failure never re-reads a CSV.
  • Dashboards as code. Superset's datasets, charts and dashboards are created entirely through its REST API; Grafana is fully provisioned from files. No UI clicking survives a rebuild.

Gold dashboard in Superset: KPI tiles and the seven business-question charts, each reading one tested gold view

Headline answers: R$ 13.49M revenue, 96,096 unique customers, November 2017 Black Friday spike, São Paulo alone at 38% of revenue, a 3.3× delivery-time gap between São Paulo (8.8 days) and Roraima (29.4 days), credit cards carrying 78% of payment value.

What I Learned

  • The hardest engineering decision wasn't a tool — it was drawing the line for where Spark's job ends. "Let Spark do everything" makes business logic untestable; Spark moves data, dbt owns logic.
  • Version pinning is not pedantry: Spark↔MinIO S3A jars must match the image's Hadoop exactly, and dbt + Airflow literally cannot share a Python environment (pip gives up). Isolate and pin, in scripts.
  • Idempotency is a feature you prove, not claim — the second green run is the evidence.