eadl:bloc5:fm3:td1

Différences

Ci-dessous, les différences entre deux révisions de la page.

Lien vers cette vue comparative

Les deux révisions précédentes Révision précédente
Prochaine révision
Révision précédente
eadl:bloc5:fm3:td1 [2026/09/16 23:34] – [6. Architecture initiale] jcheroneadl:bloc5:fm3:td1 [2026/09/17 14:29] (Version actuelle) – jcheron
Ligne 43: Ligne 43:
 ===== 3. Architecture utilisée ===== ===== 3. Architecture utilisée =====
  
-<sxh> +<html><div class='imageB'></html> 
-                         +-----------------+ +<code> 
-                         | ResourceManager | +                         ┌─────────────────┐ 
-                         |      YARN       | +                         │ ResourceManager │ 
-                         +--------+--------+ +                         │      YARN       │ 
-                                  | +                         └────────┬────────┘ 
-              +-------------------+-------------------+ +                                  │ 
-              |                   |                   | +              ┌───────────────────┼───────────────────┐ 
-       +------v------+    +-------v-----+    +--------v------+ +              │                   │                   │ 
-       | NodeManager  |    | NodeManager |    | NodeManager   | +       ┌──────▼──────┐    ┌───────▼─────┐    ┌────────▼──────┐ 
-       |  DataNode 1  |    | DataNode 2 |    |  DataNode 3   | +       │ NodeManager │    │ NodeManager │    │  NodeManager  │ 
-       +--------------+    +-------------+    +---------------+ +       │  DataNode 1 │    │  DataNode 2 │    │  DataNode 3   │ 
-              ^                   ^                   ^ +       └─────────────┘    └─────────────┘    └───────────────┘ 
-              +-------------------+-------------------+ +              ▲                   ▲                   ▲ 
-                                  | +              └───────────────────┼───────────────────┘ 
-                         +--------v--------+ +                                  │ 
-                         |    NameNode     | +                         ┌────────▼────────┐ 
-                         | Métadonnées HDFS| +                         │    NameNode     │ 
-                         +-----------------+ +                         │ Métadonnées HDFS│ 
-</sxh> +                         └─────────────────┘ 
 +</code> 
 +<html></div></html>
 ^ Composant ^ Rôle ^ ^ Composant ^ Rôle ^
 | NameNode | Gère les métadonnées HDFS | | NameNode | Gère les métadonnées HDFS |
Ligne 102: Ligne 103:
 </sxh> </sxh>
  
-Créer le fichier docker-compose-v2.yml :+copier le fichier docker-compose.yml sous **docker-compose.yml.back** :
  
 +Remplacer l'actuel **docker-compose.yml** par :  
 <sxh yml> <sxh yml>
 version: "3" version: "3"
Ligne 200: Ligne 202:
  
 <sxh bash> <sxh bash>
-docker compose -f docker-compose-v2.yml up -d+docker compose up -d
 </sxh> </sxh>
  
Ligne 206: Ligne 208:
  
 <sxh bash> <sxh bash>
-docker compose -f docker-compose-v2.yml ps+docker compose ps
 </sxh> </sxh>
  
Ligne 311: Ligne 313:
         "montant"         "montant"
     ])     ])
-date_depart = date(2026, 1, 1)+    date_depart = date(2026, 1, 1)
  
-for i in range(args.lignes): +    for i in range(args.lignes): 
-    jour = date_depart + timedelta(days=random.randint(0, 30)) +        jour = date_depart + timedelta(days=random.randint(0, 30)) 
-    commande_id = f"C{i:07d}" +        commande_id = f"C{i:07d}" 
-    client_id = f"CL{random.randint(1, 50000):05d}" +        client_id = f"CL{random.randint(1, 50000):05d}" 
-    categorie = random.choice(categories) +        categorie = random.choice(categories) 
-    ville = random.choice(villes) +        ville = random.choice(villes) 
-    montant = round(random.uniform(5, 500), 2)+        montant = round(random.uniform(5, 500), 2)
  
-    writer.writerow([ +        writer.writerow([ 
-        jour, +            jour, 
-        commande_id, +            commande_id, 
-        client_id, +            client_id, 
-        categorie, +            categorie, 
-        ville, +            ville, 
-        montant +            montant 
-    ])+        ])
 </sxh> </sxh>
  
Ligne 828: Ligne 830:
 Les fichiers Parquet doivent être relus avec Spark plutôt qu’avec ''cat''. Les fichiers Parquet doivent être relus avec Spark plutôt qu’avec ''cat''.
  
-====== Mission 10 - Synthèse de l’architecture ======+====== Mission 10 - MapReduce sur nos propres données ======
  
-Compléter :+Le ''wordcount'' précédent utilise un exemple fourni par Hadoop, sur un fichier qui n'a rien à voir avec notre contexte e-commerce. Nous allons maintenant écrire notre propre traitement MapReduce, sur ''ventes.csv'', afin de calculer le **chiffre d'affaires total par catégorie**. 
 + 
 +<WRAP tip round> 
 +Vous allez retrouver exactement le même problème que celui résolu par Spark en Mission 9 (''groupBy("categorie").agg(sum("montant"))''). L'objectif est de comparer les deux approches : MapReduce "à la main" contre Spark. 
 +</WRAP> 
 + 
 +===== 19. MapReduce ===== 
 + 
 +==== 19.1 Rappel du format des données ====
  
 <sxh> <sxh>
-Fichier de ventes +date,commande_id,client_id,categorie,ville,montant 
-       | +2026-01-05,C0000001,CL00234,informatique,Paris,120.50 
-       v +2026-01-12,C0000002,CL01998,maison,Lyon,45.90 
-   _________ +...
-   _________ +
-       | +
-       v +
-Découpage en blocs +
-       | +
-       v +
-   _________ +
-   _________ +
-       | +
-       v +
-Attribution de ressources +
-       | +
-       v +
-   _________ +
-       | +
-       v +
-Résultats stockés dans HDFS+
 </sxh> </sxh>
  
-Associer chaque composant à son rôle :+----
  
-<sxh> +==== 19.2 Écrire le mapper ==== 
-HDFS + 
-YARN +Sur la machine hôte, créer ''mapper.py'' : 
-NameNode + 
-DataNode +<sxh python> 
-ResourceManager +#!/usr/bin/env python3 
-Spark +import sys 
-MapReduce+ 
 +for line in sys.stdin: 
 +    line = line.strip() 
 + 
 +    if line.startswith("date"):  # on saute l'en-tête 
 +        continue 
 + 
 +    champs = line.split(",") 
 +    date_vente, commande_id, client_id, categorie, ville, montant = champs 
 + 
 +    # clé = catégorie, valeur = montant 
 +    print(f"{categorie}\t{montant}")
 </sxh> </sxh>
  
-====== Travail à rendre ======+----
  
-Un fichier ''compte_rendu.md'' contenant :+==== 19.3 Écrire le reducer ====
  
-===== Partie 1 - Architecture =====+Créer ''reducer.py'' :
  
-  * un schéma de l’architecture Hadoop ; +<sxh python> 
-  * le rôle de chaque composant ; +#!/usr/bin/env python3 
-  * la différence entre Hadoop, HDFS et YARN.+import sys
  
-===== Partie 2 - Blocs =====+totaux = {}
  
-  * la taille du fichier ; +for line in sys.stdin: 
-  * le nombre de blocs ; +    categorie, montant = line.strip().split("\t") 
-  * le facteur de réplication ; +    montant = float(montant) 
-  * les DataNodes utilisés ; +    totaux[categorie] = totaux.get(categorie, 0) + montant
-  * un schéma de répartition des blocs.+
  
-===== Partie 3 - Tolérance aux pannes =====+for categorie, total in sorted(totaux.items()): 
 +    print(f"{categorie}\t{total:.2f}") 
 +</sxh>
  
-  * état du cluster avant l’arrêt d’un DataNode ; +----
-  * état du cluster après l’arrêt ; +
-  * résultat de la lecture du fichier ; +
-  * explication du comportement observé.+
  
-===== Partie 4 - YARN =====+==== 19.4 Copier les scripts dans le conteneur ====
  
-  * liste des nœuds ; +<sxh bash> 
-  * observation d’une application ; +docker cp mapper.py docker-hadoop-namenode-1:/tmp/mapper.py 
-  * rôle du ResourceManager ; +docker cp reducer.py docker-hadoop-namenode-1:/tmp/reducer.py 
-  * rôle des NodeManagers ; +</sxh>
-  * explication de la notion de conteneur.+
  
-===== Partie 5 - Traitement =====+Dans le conteneur ''namenode'', rendre les scripts exécutables :
  
-  * commande de soumission ; +<sxh bash> 
-  * résultat obtenu ; +chmod +x /tmp/mapper.py /tmp/reducer.py 
-  * emplacement des résultats dans HDFS ; +</sxh>
-  * schéma du parcours des données.+
  
-===== Partie 6 - Conclusion =====+----
  
-Répondre en une dizaine de lignes :+==== 19.5 Lancer le traitement avec Hadoop Streaming ====
  
-> En quoi HDFS et YARN répondent-ils à des problèmes différents, et pourquoi sont-ils complémentaires pour exécuter un traitement distribué ?+<sxh bash> 
 +hadoop jar /opt/hadoop-3.2.1/share/hadoop/tools/lib/hadoop-streaming-*.jar \ 
 +    -input /data/ecommerce/raw/ventes/ventes.csv \ 
 +    -output /data/ecommerce/processed/ca_par_categorie_mr \ 
 +    -mapper /tmp/mapper.py \ 
 +    -reducer /tmp/reducer.py \ 
 +    -file /tmp/mapper.py \ 
 +    -file /tmp/reducer.py 
 +</sxh> 
 + 
 +<WRAP important round> 
 +Le répertoire de sortie ne doit pas déjà exister dans HDFS. Le supprimer si besoin : 
 + 
 +<sxh bash> 
 +hdfs dfs -rm -r /data/ecommerce/processed/ca_par_categorie_mr 
 +</sxh> 
 +</WRAP> 
 + 
 +<WRAP info round> 
 +Le chemin exact du jar hadoop-streaming peut varier selon l'image utilisée. Le rechercher si besoin avec : 
 +<sxh bash> 
 +find / -name "hadoop-streaming*.jar" 2>/dev/null 
 +</sxh> 
 +</WRAP> 
 + 
 +---- 
 + 
 +==== 19.6 Observer le résultat ==== 
 + 
 +<sxh bash> 
 +hdfs dfs -cat /data/ecommerce/processed/ca_par_categorie_mr/part-00000 
 +</sxh> 
 + 
 +Pendant l'exécution, consulter également : 
 + 
 +<sxh bash> 
 +yarn application -list 
 +</sxh> 
 + 
 +Répondre : 
 + 
 +  - Combien de reducers ont été utilisés ? Comment le savez-vous ? 
 +  - Ce traitement est-il apparu comme une application YARN, comme le wordcount précédent ? 
 +  - Le résultat obtenu est-il cohérent avec celui que vous avez obtenu avec Spark (Mission 9) ? 
 + 
 +---- 
 + 
 +==== 19.7 À vous de jouer — montant moyen par ville ==== 
 + 
 +On souhaite maintenant calculer le **montant moyen des ventes par ville**. 
 + 
 +<WRAP important round> 
 +**Piège classique** : on ne peut pas calculer une moyenne globale en faisant la moyenne des moyennes calculées par chaque mapper. Pourquoi ? 
 +</WRAP> 
 + 
 +Indice : le reducer doit recevoir à la fois la somme des montants et le nombre de ventes pour chaque ville, puis calculer la moyenne lui-même — pas l'inverse. 
 + 
 +==== Instructions ==== 
 + 
 +  - Modifier ''mapper.py'' pour qu'il émette ''(ville, montant)'' au lieu de ''(categorie, montant)''. 
 +  - Modifier ''reducer.py'' pour qu'il calcule une **moyenne** et non plus une somme. 
 +  - Relancer le traitement avec un nouveau répertoire de sortie : ''/data/ecommerce/processed/moyenne_par_ville''. 
 +  - Observer le résultat. 
 + 
 +==== Squelette du reducer à compléter ==== 
 + 
 +<sxh python> 
 +#!/usr/bin/env python3 
 +import sys 
 + 
 +sommes = {} 
 +compteurs = {} 
 + 
 +for line in sys.stdin: 
 +    ville, montant = line.strip().split("\t") 
 +    montant = float(montant) 
 +    # TODO : mettre à jour sommes[ville] et compteurs[ville] 
 + 
 +for ville in sorted(sommes): 
 +    moyenne = None  # TODO : calculer la moyenne 
 +    print(f"{ville}\t{moyenne:.2f}") 
 +</sxh> 
 + 
 +---- 
 + 
 +==== 19.8 Questions de synthèse ==== 
 + 
 +  - Pourquoi ne peut-on pas faire la moyenne des moyennes obtenues par chaque mapper pour obtenir la moyenne globale ? 
 +  - Combien de lignes le mapper a-t-il produites en sortie ? Combien le reducer en a-t-il produites ? 
 +  - Si vous deviez calculer le CA par catégorie **et** par ville en même temps, comment modifieriez-vous la clé émise par le mapper ? 
 +  - En quoi ce traitement est-il plus verbeux que l'équivalent Spark (''groupBy().agg()'') que vous allez écrire en Mission 9 ? Citez au moins deux différences concrètes. 
 +  - Où sont physiquement stockés les fichiers ''part-00000'' produits en sortie ? Quel composant Hadoop les a répartis sur le cluster ? 
 + 
 +<WRAP tip round> 
 +Comparez vos résultats MapReduce avec ceux de la mission 9 obtenus en Spark. 
 +</WRAP>
  
 ====== Commandes utiles ====== ====== Commandes utiles ======
Ligne 954: Ligne 1049:
 </sxh> </sxh>
  
-====== Schéma final à retenir ====== 
- 
-<sxh gutter:false> 
-                         YARN 
-             +--------------------------+ 
-             | ResourceManager          | 
-             | NodeManagers             | 
-             | Allocation des ressources| 
-             +------------+-------------+ 
-                          | 
-                          v 
-                       Spark 
-                 ou MapReduce 
-                          | 
-                          v 
-                         HDFS 
-             +-------------------------+ 
-             | NameNode                | 
-             | DataNodes               | 
-             | Blocs et réplication    | 
-             +-------------------------+ 
-</sxh> 
- 
-**HDFS stocke. YARN organise les ressources. Spark ou MapReduce traitent.** 
  • eadl/bloc5/fm3/td1.1789594440.txt.gz
  • Dernière modification : il y a 8 semaines
  • de jcheron