DE2 — Rapport de Projet Final (Track B : GitHub Archive)
Auteurs : Samba DIALLO et son binôme. Cours : Data Engineering II (Data-Intensive Workloads) - ESIEE 2025-2026
1. Cas d’usage et Dataset
Problème : Extraire des informations sur l’activité des développeurs open-source, comprendre les rythmes de publications (Push, Pull Requests) et identifier les dépôts les plus influents dans la communauté.
Dataset : GitHub Archive (Track B). Le jeu de données fournit une archive horaire (au format .json.gz) contenant la quasi-totalité des événements publics de la plateforme GitHub.
Défis : Le schéma JSON de GitHub Archive est fortement imbriqué (un champ payload polymorphe selon l’event_type) et très volumineux. Une mauvaise ingestion provoque rapidement des dépassements de mémoire (OutOfMemoryError).
2. Système et SLOs (Service Level Objectives)
- Environnement : Machine unique locale (Laptop), Spark 4.x (local[*]), Python 3.10.
- SLOs définis :
- Latence Pipeline Batch : Bronze → Gold en moins de 10 min.
- Latence Streaming : Agrégation fenêtrée en moins de 30 secondes d’intervalle.
- Latence Texte : Recherche dans l’index inversé en 2s par terme.
- Stockage : Format Parquet occupant 60% du volume du CSV brut.
- Qualité LLM : 80% des textes passent les filtres (longueur, nettoyage).
3. Architecture ETL Batch (Medallion)
L’architecture Batch repose sur 3 couches (outputs/project/) :
- Bronze (Landing) : Les événements JSON sont ingérés tels quels (bruts et immuables) depuis
data/archive/*.json.gz. - Silver (Cleaned & Typed) : On aplatit les métadonnées de base (
event_id,event_type,actor_login,repo_name,created_at). Optimisation mémoire critique : au lieu d’importer le gigantesque champ structpayload, nous n’extrayons que les champs nécessaires (le tableau des commitspayload.commitset les textes de PR) pour alléger l’empreinte de 95% et éviter le Java heap space OOM. Les données sont partitionnées pardate. - Gold (Analytics) : Une table
repo_activityagrège les événements par jour, par dépôt et par type, prête pour l’exposition BI ou via notre backend DuckDB.
4. Ingestion Streaming
Un script simule l’arrivée continue de fichiers horaires dans data/landing/.
- Source :
FileStreamSourceavecmaxFilesPerTrigger=1. - Fenêtre et Watermark : Les données sont groupées par
event_typesur une fenêtre de 5 minutes, avec un watermark de 10 minutes basé sur le champcreated_at(casté en timestamp) pour gérer les données en retard. - Sink : Écriture en mode
appendvers du Parquet, vérifiable via la capture duquery.lastProgresset l’interface Spark UI.
5. Traitement de Texte (Inverted Index)
Nous avons ciblé les messages de commit extraits des PushEvent.
- Preprocessing :
regexp_replace(normalisation alpha-numérique), split sur les espaces blancs, et suppression de stop-words courants de l’anglais et du développement logiciel. - Index Inversé : Construit via une agrégation (
collect_listdesdoc_idetcount). - Gains vs SLOs : Le stockage en Parquet est nettement plus efficace que le CSV, et le lookup d’un terme spécifique (ex: “fix”, “bug”) via Spark
filterrespecte le SLO de 2 secondes.
6. Charge Itérative : PageRank (Graphe)
Au lieu du clustering, nous avons choisi l’analyse de graphe car elle correspond à la topologie naturelle de GitHub (Développeur Dépôt).
- Graphe construit : Les arêtes sont les contributions (
PushEvent,PullRequestEvent,IssuesEvent) deactor_login(source) versrepo_name(destination). - Algorithme : PageRank itératif via jointures distribuées. À chaque itération, les nœuds redistribuent leur rang pondéré par un damping factor (0.85).
- Partitionnement : Le PageRank génère un lourd shuffle à chaque jointure. Nous avons mesuré qu’un partitionnement par hachage (
repartition(N, "src")) réduit les échanges Exchange réseau comparé à la distribution par défaut. - Convergence : La différence absolue totale () entre les rangs successifs diminue à chaque itération, confirmant la convergence.
7. Préparation des Données pour LLM
Le but est de préparer un corpus (“LLM Data Readiness”) pour du fine-tuning ou un système RAG.
- Sources textuelles : Messages de commit et corps/titres de Pull Requests.
- Filtres de qualité : Suppression des textes vides, restriction aux messages de longueur 50 caractères (pour filtrer les simples messages “fix”), et déduplication absolue via le hachage de la chaîne (
xxhash64(text)). - Plus de détails sont disponibles dans la Data Card (
data_card.md).
8. Design Physique & Optimisations
Des plans EXPLAIN FORMATTED ont été générés avant et après nos interventions.
- Sélection précoce des colonnes : Dans la couche Silver, réduire le schéma lu et éliminer les structs non nécessaires a sauvé le pipeline d’une erreur OOM.
- Partition Tuning : Le format Parquet Silver est partitionné par
date, permettant au Predicate Pushdown d’agir lors du traitement Batch. - Coût d’Exchange : Dans la charge itérative, le coût du
ShuffleExchangeExeca été contrôlé en s’assurant que les DataFrames partagent la même fonction de partition (hash partitioning).
9. Conclusion
Le pipeline complet respecte les contraintes locales et les exigences d’une architecture Medallion moderne. Les choix faits face à l’imbrication des JSON de GitHub prouvent que l’analyse du schéma (printSchema()) est cruciale. L’intégration de DuckDB (hors notation, pour le backend) permet en aval une exploitation sans latence des couches Gold produites par Apache Spark.