Skip to content

Commit

Permalink
Create partie2.md
Browse files Browse the repository at this point in the history
  • Loading branch information
hrhouma authored Sep 23, 2024
1 parent 9b39919 commit 7145d14
Showing 1 changed file with 192 additions and 0 deletions.
192 changes: 192 additions & 0 deletions B13-examen-mi-session-01/partie2.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,192 @@
# proposition de réponse 1


Le code proposé est fonctionnel, mais il y a plusieurs aspects qui peuvent être optimisés pour améliorer la lisibilité, la performance et la sécurité du code. Voici quelques recommandations :

1. **Utilisation de `val` au lieu de `var` :**
- **Pourquoi ?** : En Scala, il est préférable d’utiliser `val` pour déclarer des variables immuables. Cela rend le code plus sûr et évite les erreurs liées à des modifications inattendues des variables.
- **Dans ce code** : Toutes les variables (`conf`, `sc`, `lines`, etc.) ne sont pas modifiées après leur initialisation. Il est donc conseillé d’utiliser `val` à la place de `var`.

```scala
val conf = new SparkConf().setAppName("RDD Example").setMaster("local[*]")
val sc = new SparkContext(conf)
```

2. **Fermeture du SparkContext (`sc.stop()`) :**
- **Pourquoi ?** : Ne pas fermer explicitement le SparkContext peut entraîner des fuites de mémoire et des problèmes de gestion de ressources, surtout lorsque le code est exécuté plusieurs fois. Il est donc essentiel d’appeler `sc.stop()` à la fin de l'exécution.

```scala
sc.stop()
```

3. **Améliorer la performance avec `cache()` ou `persist()` :**
- **Pourquoi ?** : Lorsque vous travaillez avec des données volumineuses, il est souvent plus efficace de mettre en mémoire certaines étapes intermédiaires pour éviter de recalculer les résultats à chaque fois. Utiliser `cache()` permet de stocker les RDDs en mémoire pour les réutiliser sans les recalculer.

```scala
val wordCounts = wordPairs.reduceByKey(_ + _).cache()
```

4. **Gestion des données volumineuses :**
- **Problème** : L’utilisation de `collect()` sur des données volumineuses peut entraîner des dépassements de mémoire car tous les résultats sont ramenés sur le driver.
- **Solution** : Si les données sont trop volumineuses, il est préférable d'écrire les résultats dans un fichier avec `saveAsTextFile()` plutôt que de tout afficher directement.

```scala
sortedByLength.saveAsTextFile("sorted_results.txt")
```

5. **Gestion des erreurs avec `try-catch` :**
- **Pourquoi ?** : En environnement de production, il est important de gérer les exceptions pour éviter que le programme ne se termine de manière imprévue. Implémenter une structure de gestion d’erreurs permet de capturer et gérer les exceptions de manière appropriée.

```scala
try {
// Le code Spark
} catch {
case e: Exception => println(s"Erreur lors de l'exécution : ${e.getMessage}")
} finally {
sc.stop() // Toujours fermer SparkContext
}
```

6. **Amélioration de la lisibilité et de la maintenabilité :**
- **Proposition** : Découper le code en plusieurs fonctions pour rendre le code plus lisible et plus maintenable. Cela permet aussi de réutiliser certaines parties du code plus facilement.

Exemple de code refactorisé :

```scala
import org.apache.spark.{SparkConf, SparkContext}

object RDDExample {
def main(args: Array[String]): Unit = {
val conf = new SparkConf().setAppName("RDD Example").setMaster("local[*]")
val sc = new SparkContext(conf)

val lines = loadLines(sc, "large_dataset.txt")
val wordCounts = countWords(lines)
val sortedByLength = sortByLength(wordCounts)
sortedByLength.saveAsTextFile("sorted_results.txt")

sc.stop()
}

def loadLines(sc: SparkContext, path: String): RDD[String] = sc.textFile(path)

def countWords(lines: RDD[String]): RDD[(String, Int)] =
lines.flatMap(_.split(" ")).map((_, 1)).reduceByKey(_ + _)

def sortByLength(wordCounts: RDD[(String, Int)]): RDD[(Int, (String, Int))] =
wordCounts.map { case (word, count) => (word.length, (word, count)) }.sortByKey()
}
```

7. **Gestion de la casse des mots** :
- **Problème** : Le code actuel considère « Bonjour » et « bonjour » comme deux mots différents.
- **Solution** : Il est recommandé de normaliser les mots en minuscule (ou majuscule) avant de les compter.

```scala
val words = lines.flatMap(_.toLowerCase.split(" "))
```

### Conclusion :
Ces optimisations améliorent la lisibilité, la performance et la robustesse du code, en particulier dans un contexte de big data. En appliquant ces recommandations, le code sera non seulement plus efficace, mais aussi plus facile à maintenir.



# proposition de réponse 2



Le code fourni est globalement correct et fonctionnel pour le traitement de données textuelles à l'aide de Spark. Cependant, plusieurs améliorations peuvent être apportées pour optimiser les performances et assurer une meilleure pratique en programmation. Voici un retour détaillé sur les points à corriger ou à améliorer :

---

#### **1. Utilisation de `val` au lieu de `var` (Immutabilité)** :
Il est recommandé d’utiliser `val` plutôt que `var` pour les variables qui ne sont pas destinées à être modifiées. Dans ce code, les variables comme `conf`, `sc`, `lines`, et `wordCounts` sont immuables une fois créées. L’utilisation de `val` permet de garantir la sécurité du code, d’éviter des modifications accidentelles et de faciliter la maintenance.

**Exemple** :
```scala
val conf = new SparkConf().setAppName("RDD Example").setMaster("local[*]")
val sc = new SparkContext(conf)
```

---

#### **2. Fermeture du SparkContext** :
Il est essentiel de fermer le SparkContext à la fin de l'exécution du programme pour libérer les ressources. Ne pas fermer le contexte Spark peut entraîner des fuites de mémoire ou des erreurs lors de l'exécution répétée du code. Ajoutez la ligne suivante à la fin de votre programme :

```scala
sc.stop()
```

---

#### **3. Gestion des erreurs (try-catch)** :
Dans un projet Big Data, les erreurs peuvent survenir à divers moments, notamment lors de la lecture de fichiers volumineux ou de la manipulation des données. L’ajout d’une gestion des exceptions avec un bloc `try-catch` permet de capturer ces erreurs et de fournir des messages d’erreur explicites. Cela est particulièrement utile dans un environnement de production.

**Exemple** :
```scala
try {
val lines = sc.textFile("large_dataset.txt")
} catch {
case e: Exception => println(s"Erreur lors de la lecture du fichier : ${e.getMessage}")
}
```

---

#### **4. Optimisation de l'opération `collect()`** :
L'opération `collect()` récupère tous les résultats dans le driver, ce qui peut causer des problèmes de mémoire si le volume de données est très important. Il est préférable d'utiliser des alternatives comme `take(n)` pour récupérer une partie des résultats, ou d’écrire les résultats dans un fichier via `saveAsTextFile` si vous devez gérer des données volumineuses.

**Exemple** :
```scala
sortedByLength.saveAsTextFile("output_directory")
```

---

#### **5. Gestion des mots avec différentes casses (majuscule/minuscule)** :
Actuellement, le code traite les mots comme distincts s'ils sont en majuscules ou en minuscules. Il est conseillé de normaliser la casse des mots (tout en minuscules ou tout en majuscules) pour éviter que des mots comme "Bonjour" et "bonjour" ne soient considérés comme différents.

**Exemple** :
```scala
val words = lines.flatMap(line => line.toLowerCase.split("\\s+"))
```

---

#### **6. Optimisation avec `cache()` ou `persist()`** :
Dans un contexte de Big Data, certaines transformations sont réutilisées à plusieurs reprises. Pour éviter de recalculer ces transformations à chaque fois, il est conseillé d'utiliser la méthode `cache()` ou `persist()` pour stocker les RDD en mémoire. Cela peut grandement améliorer les performances, surtout si les transformations intermédiaires sont lourdes.

**Exemple** :
```scala
val wordCounts = wordPairs.reduceByKey(_ + _).cache()
```

---

#### **7. Refonte pour améliorer la lisibilité du code** :
Il peut être bénéfique de refactorer le code pour le rendre plus modulaire et lisible. Par exemple, diviser le code en plusieurs fonctions permet de mieux structurer le traitement des données.

**Exemple de refactorisation** :
```scala
def loadLines(sc: SparkContext, path: String): RDD[String] = sc.textFile(path)

def countWords(lines: RDD[String]): RDD[(String, Int)] = {
lines.flatMap(_.split(" ")).map((_, 1)).reduceByKey(_ + _)
}

def sortByLength(wordCounts: RDD[(String, Int)]): RDD[(Int, (String, Int))] = {
wordCounts.map { case (word, count) => (word.length, (word, count)) }.sortByKey()
}

def displayResults(results: Array[(Int, (String, Int))]): Unit = {
results.foreach { case (length, (word, count)) =>
println(s"Word: $word, Length: $length, Count: $count")
}
}
```

---

### **Conclusion** :
En suivant ces améliorations, le code sera non seulement plus sûr et maintenable, mais il sera aussi mieux adapté pour traiter de grandes quantités de données. L’utilisation de bonnes pratiques comme l'immutabilité (`val`), la gestion des erreurs (`try-catch`), et l’optimisation des opérations coûteuses en mémoire (`cache()`, `saveAsTextFile()`) est cruciale pour garantir un traitement performant et fiable des données dans un projet Big Data.

0 comments on commit 7145d14

Please sign in to comment.