← All work

DATA ENGINEERING · RECOMMENDATIONS

Splitting a 411.7M-event pipeline into restartable jobs

I built REES46 V2 to turn historical shopping events into recommendations served by a local API. When the first aggregation filled the disk, I split the pipeline so finished work could survive a retry.

411.7MBronze events processed
410.3Mcanonical Silver events
5,000held-out ranking test users
REES46 / DATA ARCHITECTURE01
B
Bronze411,709,736 historical events
RAW → PARQUET
S
Silver410,325,314 canonical events
VALIDATE / DEDUP
G
Monthly GoldPartitioned, restartable outputs
FEATURES / FACTS
Then: retrieval → ranking → local API
PROJECT CONTEXT

REES46 V2

My first aggregation ran out of temporary storage. I split the work by month and session bucket so I could reuse finished work after a retry.

  • Python
  • DuckDB
  • Parquet
  • FastAPI
Independent project / controlled lab

The problem

I wanted to understand the path from messy shopping events to useful recommendations. That meant ingestion, quality checks, deduplication, features, retrieval, ranking and evaluation, rather than starting with a tidy model-ready table.

Why I split the aggregation

The first global Gold aggregation over roughly 410 million Silver events exhausted temporary storage after a ~30.6 GiB DuckDB spill. I redesigned the work around monthly partitions so a failure would have a smaller recovery boundary.

Ordered session aggregation needed another step. I split monthly sessions into 64 deterministic hash buckets on user_session and aggregated one bucket at a time. Keeping a session in one bucket preserved the ordering contract while bounding the aggregate state.

Completed outputs are written atomically and reused on restart. The aim was to make the computation fit the machine and make retries predictable.

Bronze, Silver, and Gold outputs

The Bronze layer processed 411,709,736 events from October 2019 to April 2020. Removing 1,384,422 exact duplicates left 410,325,314 canonical Silver events. Monthly Gold outputs include user-item interactions, item and user statistics, category affinity and session sequences.

The modeling path compares popularity, co-visitation, collaborative retrieval, hybrid retrieval and purchase ranking. MLflow records experiments. A local FastAPI service exposes the chosen bundle with an explicit popularity fallback for unknown users.

The separate offline benchmark

Data-processing scale and model-evaluation scale are different. The ranking experiment used 1,499,021 training interactions, 50,000 training sessions, 5,000 validation users and 5,000 held-out test users.

Training covered October–February, validation used March, and final testing used April 2020.

April 2020 offline benchmark · higher is better
MetricPopularityPurchase ranker
MRR@200.024430.03556
Recall@100.056850.07087
NDCG@200.035930.04429

Absolute ranking quality remains modest. These results describe the defined offline test; they do not establish online engagement, revenue, or users served by a live production service.

What I would work on next

I would investigate candidate recall, cold-start behavior, and realistic latency and memory benchmarks before treating this as a deployed recommendation service. Online experiments, continuous retraining and freshness guarantees remain future work.

Source & evidence

Code, experiment results, and implementation notes.

NEXT CASE STUDYFulfillAI