M2 Data Engineering

Projet intégrateur — StreamCity Analytics

M2 DAT · 2025-2026 · Projet 4 jours en équipe de 2
✦ Projet intégrateur — Spark · Elasticsearch · Kibana · MapReduce

StreamCity Analytics — Pipeline de données distribué sur les trajets de taxi à New York

La TLC (Taxi & Limousine Commission) de New York publie chaque mois les données de tous les trajets de taxi de la ville. Votre mission : construire un pipeline data end-to-end — ingestion distribuée avec Spark, indexation dans Elasticsearch, visualisation dans Kibana — et confronter Spark à MapReduce/YARN sur une même agrégation pour en mesurer l'écart de performance.

⚡ Apache Spark 🔍 Elasticsearch 📊 Kibana 🗺️ MapReduce / YARN 🗽 NYC TLC — Données publiques
👥 Équipes de 2
📅 4 jours
🏆 100 pts + bonus
🎤 Soutenance 25 min
📦 5 livrables

🎯 Choix pédagogique — Pourquoi cette combinaison de technologies ?

Cassandra est exclu de ce projet. Cassandra excelle dans le write-heavy en temps réel et la haute disponibilité en production — mais sa pertinence n'est pas démontrable en 4 jours sur un dataset batch historique. Le faire mal serait contre-productif. Ce projet mobilise les technologies les plus cohérentes avec le dataset et les objectifs pédagogiques.
TechnologieRôle dans ce projetPourquoi ce choix
⚡ Apache SparkETL distribué — lecture, nettoyage, enrichissement, agrégations des fichiers ParquetVolume de données justifiant la distribution. Spark SQL, DataFrames, optimisation des jobs. Cœur du projet.
🔍 ElasticsearchIndex de recherche et d'analyse — stockage des données agrégées et brutes pour KibanaComplémentarité naturelle avec Spark (connector officiel). Permet le full-text search + analytics sur les données géospatiales NYC.
📊 KibanaDashboard de visualisation temps réel alimenté par ElasticsearchCouplage natif avec ES. Visualisations géospatiales, time series, histogrammes — idéaux pour les données de taxi.
🗺️ MapReduce / YARNImplémentation Java d'une agrégation de référence — comparaison de performance avec SparkPédagogique : faire tourner le même calcul en MR Java puis en Spark et mesurer l'écart. Rend concret l'apport de Spark.

Architecture du pipeline — Vue globale

📦 Source

Parquet NYC TLC
~20 M lignes/mois
Stockage HDFS / local

🗺️ MapReduce

Agrégation Java
Reference benchmark
YARN resource manager

⚡ Spark ETL

Nettoyage, enrichissement
Agrégations optimisées
Spark SQL + DataFrames

🔍 Elasticsearch

Index structuré
Mapping géospatial
Indexation Spark→ES

📊 Kibana

Dashboard live
Geo heatmap
Time series + KPIs

📂 Dataset — NYC TLC Trip Record Data

Les données sont publiées mensuellement par la Taxi & Limousine Commission de New York. Format Parquet, disponibles sans inscription depuis 2009. Pour ce projet, utiliser 3 mois consécutifs de 2023 (janvier à mars), soit environ 60 millions de trajets.

~20M
Trajets / mois
~3 Go
Par fichier Parquet
~9 Go
Volume total projet
19
Colonnes clés
265
Zones géographiques (PULocationID)
Gratuit
Aucune inscription requise
# Téléchargement des 3 fichiers Parquet (Yellow Taxi — 2023) wget https://d37ci6vzurychx.cloudfront.net/trip-data/yellow_tripdata_2023-01.parquet wget https://d37ci6vzurychx.cloudfront.net/trip-data/yellow_tripdata_2023-02.parquet wget https://d37ci6vzurychx.cloudfront.net/trip-data/yellow_tripdata_2023-03.parquet # Dictionnaire des zones géographiques (pour enrichissement) wget https://d37ci6vzurychx.cloudfront.net/misc/taxi_zone_lookup.csv # Chargement rapide pour exploration initiale from pyspark.sql import SparkSession spark = SparkSession.builder.appName("StreamCity").getOrCreate() df = spark.read.parquet("data/yellow_tripdata_2023-*.parquet") df.printSchema() print(f"Nombre de trajets : {df.count():,}")

Colonnes clés et enjeux d'ingénierie

ColonneTypeEnjeu data engineering
tpep_pickup_datetimeTimestampExtraction heure/jour/semaine/mois. Filtrage des dates aberrantes (> 2023 ou < 2020). Clé de partitionnement.
tpep_dropoff_datetimeTimestampCalcul de la durée du trajet. Détection des durées impossibles (< 30s ou > 6h).
trip_distanceDoubleValeurs négatives ou nulles à filtrer. Outliers (distance > 100 miles = probable erreur GPS).
PULocationID / DOLocationIDIntegerJoin avec taxi_zone_lookup.csv pour enrichir Borough et Zone. Clé pour les analyses géospatiales.
fare_amountDoubleValeurs négatives (anomalies), zéros, outliers. Nettoyage strict nécessaire avant agrégation.
payment_typeInteger (1–6)Encodage à mapper (1=Card, 2=Cash, 3=No charge, 4=Dispute…). Analyse de la préférence de paiement.
passenger_countDouble (nullable)Valeurs nulles fréquentes depuis 2022 (enregistrement automatisé). Imputation ou exclusion à justifier.
congestion_surchargeDoubleDonnées manquantes pré-2019. Indicateur de zone congestionnée (Manhattan core).
⚠️ Données connues pour leurs anomalies : Le dataset NYC TLC contient intentionnellement des données sales — dates futures, montants négatifs, distances nulles avec tarifs positifs. C'est un atout pédagogique : le pipeline doit gérer ces cas explicitement et les documenter dans un rapport de qualité des données.
J1

MapReduce / YARN — Le benchmark de référence

Implémenter l'agrégation de référence en Java MapReduce, la soumettre sur YARN, mesurer les performances.

Java · Hadoop MapReduce · YARN
Objectif pédagogique du Jour 1 : Comprendre de l'intérieur pourquoi MapReduce est limité — verbosité du code Java, modèle batch rigide, pas de caching en mémoire. Ce constat motivera le passage à Spark le Jour 2. On ne fait pas MapReduce pour souffrir — on le fait pour mesurer.

La tâche MapReduce à implémenter

Agrégation cible : Pour chaque zone de prise en charge (PULocationID) et chaque heure de la journée, calculer le nombre de trajets, le montant moyen et la distance moyenne. Cette même agrégation sera réimplémentée en Spark le Jour 2 — la comparaison sera directe.
1
Setup environnement — Hadoop en mode pseudo-distribué

Configurer Hadoop (HDFS + YARN) en mode pseudo-distribué ou utiliser un cluster fourni. Copier les données sur HDFS. Vérifier le ResourceManager et le NodeManager.

hdfs dfs -puthadoop confYARN ResourceManager
2
Implémentation Java — Mapper, Reducer, Driver

Écrire les 3 classes Java : Mapper (lit chaque ligne CSV, émet <zone_heure, tarif,distance,1>), Reducer (agrège par clé), Driver (configure le job). Compiler et packager en JAR.

Java 8Mapper / Reducermvn package
3
Soumission sur YARN et mesure des performances

Soumettre le job avec hadoop jar. Monitorer via l'interface YARN ResourceManager (port 8088). Mesurer : durée totale, temps Map, temps Reduce, octets lus/écrits.

YARN UI :8088hadoop jarcounters
4
Documentation du benchmark

Capturer toutes les métriques YARN (elapsed time, map time, reduce time, bytes read). Ces chiffres seront comparés aux résultats Spark Jour 2. Exporter les résultats en CSV pour validation croisée.

Job countersmetrics export
💡 Livrable Jour 1 : JAR compilé + résultats MapReduce validés + tableau de métriques YARN (temps d'exécution, bytes lus/écrits, nombre de map/reduce tasks). Ce tableau sera le point de comparaison du Jour 2.
J2

Apache Spark — ETL distribué et comparaison

Réimplémenter la même agrégation en Spark, puis étendre le pipeline à un ETL complet avec enrichissement et partitionnement.

PySpark · Spark SQL · Spark UI
1
Même agrégation qu'en MapReduce — mais en Spark

Reproduire exactement la même agrégation (zone × heure → count, avg_fare, avg_distance) en Spark DataFrame API. Mesurer le temps d'exécution. Comparer les résultats ligne à ligne pour valider la cohérence.

DataFrame APIgroupBy / aggSpark UI

Le même calcul, deux approches

🗺️ MapReduce Java (Jour 1)
  • ~120 lignes de code Java
  • 3 classes distinctes (Mapper, Reducer, Driver)
  • Lecture ligne par ligne depuis HDFS
  • Pas de cache — tout repasse par disque
  • Optimisation manuelle requise
⏱️ Temps mesuré Jour 1 : ____ min
⚡ Spark PySpark (Jour 2)
  • ~15 lignes de code Python
  • API DataFrame unifiée
  • Lecture Parquet native (colonnes + predicates)
  • Cache mémoire RDD automatique
  • Optimiseur Catalyst intégré
⏱️ Temps mesuré Jour 2 : ____ min → ratio à documenter
2
Spark SQL — Requêtes analytiques avancées

Enregistrer le DataFrame en vue temporaire et écrire 5 requêtes SQL complexes : zones les plus rentables par heure, corrélation distance/tarif par borough, impact des jours fériés sur le volume, détection des heures creuses.

createTempViewSpark SQLwindow functions
3
Optimisation Spark — Catalyst et Tungsten

Analyser les plans d'exécution (explain()). Tester l'impact du partitionnement, du cache et du broadcast join. Documenter les optimisations appliquées et leur impact mesuré sur le Spark UI.

explain(True)cache()broadcast()Spark UI :4040
💡 Livrable Jour 2 : Script Spark Python commenté + tableau de comparaison MapReduce vs Spark (temps, lignes de code, ressources consommées) + plans d'exécution Catalyst avant/après optimisation + captures Spark UI.
J3

Elasticsearch & Kibana — Indexation et visualisation

Définir le mapping ES, indexer les données via Spark, construire le dashboard Kibana.

Elasticsearch · Kibana · spark-elasticsearch-connector
1
Mapping Elasticsearch — Typage précis des champs

Créer 2 index avec leurs mappings : nyc_trips (données brutes échantillonnées) et nyc_agg_zone_hour (agrégations). Typer correctement les champs géospatiaux, temporels et numériques.

PUT mappinggeo_pointdate format

Mapping Elasticsearch — Index trips

Le mapping ci-dessous définit le schéma de l'index ES. Les champs geo_point permettront les visualisations cartographiques dans Kibana. Le champ @timestamp active les fonctionnalités time-series natives.
2
Indexation via Spark — Connector elasticsearch-spark

Utiliser le connector officiel Elasticsearch-Hadoop pour écrire directement depuis Spark vers ES sans passer par un script intermédiaire. Configurer le batch size et la parallélisation.

spark-submitelasticsearch-sparkes.nodes
3
Dashboard Kibana — 4 visualisations minimum

Construire le dashboard Kibana en connectant les deux index créés. Utiliser les visualisations cartographiques, time series, et histogrammes pour répondre aux questions business.

MapsTSVBLensAggregation-based

Visualisations Kibana à produire

Maps
Heatmap des prises en charge

Densité des départs par zone géographique. Filtrable par heure, borough, type de paiement.

TSVB Time Series
Volume de trajets dans le temps

Évolution heure par heure sur 3 mois. Détection des pics (rush hours, weekends, événements).

Lens Bar Chart
Recette moyenne par Borough

Comparaison Manhattan vs Brooklyn vs Queens. Décomposition par heure de la journée.

Lens Donut
Répartition des paiements

Card vs Cash par borough. Évolution dans le temps (adoption du paiement carte).

Aggregation Table
Top 10 zones les plus actives

Classement des zones par volume de trajets, tarif moyen, durée moyenne. Drill-down disponible.

Gauge / KPI
KPIs opérationnels

Total trajets indexés, tarif moyen global, % rush hour, durée médiane. Vue temps réel.

💡 Livrable Jour 3 : Mapping ES exporté (JSON) + commandes d'indexation documentées + fichier d'export du dashboard Kibana (ndjson) + captures d'écran des 6 visualisations. Le dashboard doit fonctionner avec des filtres dynamiques.
J4

Rapport technique, insights et soutenance

Synthétiser l'architecture, analyser les résultats, rédiger les recommandations et défendre le projet.

Rapport · Slides · Démo live · 25 min
1
Rapport d'architecture — Documentation du pipeline

Schéma d'architecture complet, justification des choix techniques, rapport de qualité des données (anomalies trouvées, traitements appliqués), tableau de comparaison MapReduce/Spark commenté.

MR benchmarkSpark metrics
2
Insights analytiques — Ce que les données révèlent

3 insights business concrets sur le marché du taxi NYC : patterns de rush hour, zones sous-exploitées, évolution du cashless, impact météo (si enrichissement données météo intégré en bonus).

Kibana insightsSpark SQL
3
Soutenance — Architecture × Performance × Dashboard

15 slides max. Structure : contexte data engineering → architecture → MR benchmark → Spark ETL + résultats → ES/Kibana démo live → recommandations d'amélioration. Démo live du dashboard Kibana obligatoire.

Démo live Kibana

🏆 Grille de Notation

🗺️ MapReduce / YARN (Jour 1)
20 pts
Code Java fonctionnel et correct (Mapper, Reducer, Driver)
/ 8 pts
Soumission réussie sur YARN + résultats cohérents
/ 6 pts
Métriques YARN documentées (temps, bytes, tasks)
/ 3 pts
Gestion des erreurs de parsing et compteurs de qualité
/ 3 pts
⚡ Apache Spark ETL (Jour 2)
30 pts
Nettoyage des données — filtres justifiés et documentés
/ 6 pts
Feature engineering (temporel, enrichissement zones, rush hour)
/ 6 pts
Agrégations Spark SQL pertinentes (min. 5 requêtes)
/ 6 pts
Optimisations appliquées et mesurées (plan Catalyst, cache, broadcast)
/ 6 pts
Comparaison MapReduce vs Spark — analyse quantitative et qualitative
/ 6 pts
🔍 Elasticsearch + 📊 Kibana (Jour 3)
30 pts
Mapping ES correct (types, geo_point, keyword vs text)
/ 7 pts
Indexation fonctionnelle via Spark connector (count cohérent)
/ 7 pts
Dashboard Kibana — 6 visualisations pertinentes et interactives
/ 8 pts
Requêtes DSL Elasticsearch documentées (au moins 3)
/ 4 pts
Cohérence ES → Kibana (les données indexées correspondent aux visuels)
/ 4 pts
🎤 Soutenance + Rapport (Jour 4)
20 pts
Clarté de l'architecture présentée et cohérence globale du pipeline
/ 6 pts
Démo live Kibana — navigation fluide, réponses aux questions du jury
/ 5 pts
Qualité des insights analytiques (au-delà du technique)
/ 4 pts
Rapport technique — qualité de données + justifications des choix
/ 5 pts

Bonus et pénalités

+4 pts
Spark Structured Streaming — simuler un flux temps réel en rejouant les données en micro-batch et les envoyer dans ES en quasi-temps réel avec writeStream
+3 pts
Enrichissement météo — joindre les données NYC TLC avec un dataset météo public (NOAA) pour analyser l'impact de la pluie/neige sur le volume de trajets et les tarifs
+3 pts
Alertes Kibana — configurer au moins 2 alertes Kibana (ex : volume de trajets en dessous d'un seuil, tarif moyen anormalement élevé) avec notification simulée
+2 pts
Combinator MapReduce → Spark — utiliser un Combiner local dans le job MapReduce pour réduire le trafic réseau, mesurer l'impact sur la performance et comparer avec le Spark broadcast join
−5 pts
Mapper MapReduce qui lit les fichiers Parquet natifs sans conversion préalable — MR Java ne lit pas Parquet nativement, preuve que le pipeline n'a pas été testé
−4 pts
Index Elasticsearch avec tous les champs en type text — absence de compréhension des types ES (keyword, integer, geo_point) empêchant les agrégations Kibana
−3 pts
Pipeline Spark → ES via export CSV intermédiaire + script Python de bulk insert — le connector Spark doit être utilisé directement
−3 pts
Dashboard Kibana sans filtre temporel ou sans interaction croisée — utilisation basique sans démonstration de maîtrise de l'outil

Barème de conversion

17–20
85–100 pts
14–16
70–84 pts
11–13
55–69 pts
8–10
40–54 pts
0–7
< 40 pts

🎤 Questions Potentielles en Soutenance

Questions posées individuellement à chaque membre. Les deux membres doivent maîtriser l'intégralité du pipeline.

🗺️ MapReduce / YARN
  • Pourquoi avoir converti les fichiers Parquet avant de les passer à MapReduce ? Qu'aurait-il fallu faire autrement ?
  • Expliquez le rôle du Combiner dans un job MapReduce. Aurait-il été utile ici ?
  • Comment le YARN ResourceManager a-t-il réparti votre job entre les Map tasks et les Reduce tasks ? Que montre l'interface à :8088 ?
⚡ Apache Spark
  • Expliquez la différence entre un DAG Spark et la séquence Map/Shuffle/Reduce de Hadoop. Pourquoi Spark est-il plus rapide sur ce cas ?
  • Qu'est-ce que le Catalyst optimizer ? Montrez-nous un plan physique depuis votre explain() et expliquez une décision d'optimisation visible.
  • Vous avez partitionné par mois et borough — quel impact cela a sur les lectures futures ? Qu'auriez-vous choisi comme partition si vous deviez optimiser pour les requêtes Kibana ?
  • Pourquoi avoir utilisé sample(0.05) avant d'indexer dans ES ? Quels sont les trade-offs ?
🔍 Elasticsearch
  • Quelle est la différence entre un champ keyword et un champ text dans le mapping ES ? Pourquoi PUBorough est-il en keyword et non en text ?
  • Vous avez créé 3 shards — comment ES répartit-il les documents entre les shards ? Sur quel critère ?
  • Écrivez la requête DSL qui retourne le tarif moyen par borough pour les trajets de plus de 5 km un mardi.
📊 Kibana
  • Comment Kibana sait-il que @timestamp est votre champ temporel ? Que se passe-t-il si vous l'oubliez dans le mapping ?
  • Quelle visualisation Kibana permet les agrégations géospatiales ? Quel type de champ ES est requis ?
  • Si un ingénieur vous demande de mettre à jour le dashboard chaque nuit avec les nouvelles données du jour, comment architecturez-vous la mise à jour du pipeline ?

📦 Récapitulatif des 5 livrables à remettre

☕ Job MapReduce Java

taxijob/ — Sources Java + JAR compilé + résultats HDFS + capture YARN UI + tableau métriques.

⚡ Scripts Spark

spark/etl.py + analytics.py + plans d'exécution Catalyst + tableau comparaison MR/Spark.

🔍 Index Elasticsearch

elasticsearch/ — Fichiers de mapping JSON + script d'indexation + requêtes DSL documentées.

📊 Dashboard Kibana

kibana_export.ndjson — Export du dashboard (6 visuels) + captures d'écran + guide d'import.

📄 Rapport + Slides

rapport.pdf + slides.pdf — Architecture, rapport qualité données, benchmark MR/Spark, recommandations, 15 slides max.

Format de dépôt : StreamCity_[NomEquipe].zip · Scripts exécutables avec README d'installation · Démo live Kibana pendant la soutenance (cluster disponible ou screenshot vidéo si indisponible)

Ce qu'on évalue — En résumé

MR / YARNCode Java correct et fonctionnel · Soumission YARN réussie · Métriques documentées · Servir de référence comparative
SparkPipeline ETL robuste · Feature engineering pertinent · Optimisations mesurées · Résultats cohérents avec MapReduce
ElasticsearchMapping typé correctement · Indexation via connector Spark · Requêtes DSL maîtrisées · Index cohérent avec Kibana
Kibana6 visualisations pertinentes · Interactivité réelle · Démo live maîtrisée · Réponse aux questions business
CohérencePipeline end-to-end fonctionnel · MR et Spark produisent les mêmes résultats · ES alimente réellement Kibana

Dataset : NYC TLC Trip Record Data · ~60M trajets · 3 mois 2023 · Données publiques — aucune inscription requise