Blog ENI : Toute la veille numérique !
🐠 -25€ dès 75€ 
+ 7 jours d'accès à la Bibliothèque Numérique ENI. Cliquez ici
Accès illimité 24h/24 à tous nos livres & vidéos ! 
Découvrez la Bibliothèque Numérique ENI. Cliquez ici
  1. Livres et vidéos
  2. Apache Spark
  3. Industrialiser Spark
Extrait - Apache Spark Développez en Python pour le big data
Extraits du livre
Apache Spark Développez en Python pour le big data Revenir à la page d'achat du livre

Industrialiser Spark

Améliorer les performances de temps

1. Dimensionner adéquatement le cluster

Vous avez vu la manière dont la distribution est rendue possible dans le framework ainsi que les méthodes qui vous permettent de faire de l’enrichissement de données et de l’apprentissage automatique. À présent, nous allons voir les techniques pour partir sereinement en production avec Spark. Nous commencerons par rappeler des principes que nous avons vus dans les chapitres précédents.

Spark est un framework distribué capable de traiter de forts volumes de données. Cela ne signifie pas pour autant que vous ne rencontrerez jamais de problèmes de performances. Les spécifications de votre cluster ont en premier lieu un impact sur celles-ci. S’il est sous-dimensionné, en termes de mémoire par exemple, par rapport à la quantité d’informations que vous voulez traiter, vous risquez d’avoir des problèmes.

2. Choisir la bonne API

Une fois que vous avez paramétré votre cluster de manière adéquate, vous pouvez suivre quelques principes qui vous éviteront des désagréments.

Nous avons longuement parlé des API DataFrame, Dataset et RDD. Les deux premières sont à privilégier. Elles contiennent un moteur d’optimisation qui fait toute la différence. Les objets RDD ne doivent être utilisés qu’en tout dernier recours. Si vous avez l’habitude de développer avec Scala et que vous avez besoin de performances plus que de robustesse à la compilation, l’API DataFrame est alors indiquée. Vous perdrez vos types, mais gagnerez en performances. La différence est cependant moindre entre les API DataFrame et Dataset qu’entre les API haut niveau et bas niveau. C’est même très peu comparable en réalité.

3. Éviter les UDF

Les UDF qui vous permettent d’ajouter votre propre logique dans le moteur Spark. Évitez-les au maximum. Le framework contient de nombreuses fonctions que vous pouvez assembler pour parvenir à différentes fins. Si toutefois vous ne pouvez couper à la création d’une UDF, cantonnez-la à une forme simple, sans effet de bord, et testez-la comme n’importe quel autre morceau de code.

4. User précautionneusement...

Tester avec Spark

1. Tester sans Spark

Il est assez rare de ne pas avoir besoin de tester automatiquement un programme. Sauf si vous développez quelque chose d’expéditif voué à ne plus être utilisé dans les semaines à venir, un bouclier de tests automatisés est indispensable. Nous allons voir quelques astuces qui vous aideront à tester vos programmes avec Spark.

Nous parlerons ici de tests unitaires.

Nous basculons dans Scala pour un instant. Supposons que nous travaillons avec l’API Dataset. Nous créons une case class nommée Diamant.

case class Diamant(couleur: String, prix: Int) 

Nous téléchargeons un fichier auquel nous appliquons la case class Diamant et obtenons ainsi un Dataset.

val diamants: Dataset[Diamant] = 
spark.read.csv("diamants.csv").as[Diamant] 

Nous voulons à présent récupérer uniquement la couleur du diamant.

val result: Dataset[String] = diamants.map(diamant => { 
  diamant.couleur 
}) 

Ici, il est possible de tester cette partie de code sans faire intervenir Spark. Ce que nous voulons vérifier, c’est notre capacité à extraire la couleur. Or, nous pouvons déplacer ce code dans une fonction.

def selectionneCouleur(diamant: Diamant): String = { 
  diamant.couleur 
} 

Nous l’utilisons ensuite.

val resultat: Dataset[String] = diamants.map(selectionneCouleur(_)) 

Nous effectuons un test sur la fonction selectionneCouleur. Aucune intervention de Spark n’est nécessaire. Nous pouvons imaginer une forme de test comme suit :

val couleur = selectionneCouleur(unDiamant) 
assert couleur == "rouge" 

2. Tester avec Spark

Tester se complique quand vous avez besoin d’aller plus loin que tester du code isolé dans des fonctions. Supposons que nous voulons joindre les diamants avec les couleurs tendance de l’année, puis extraire le prix de cette jointure. Il s’agit de se faire une idée des tarifs des pierres précieuses ayant les pigments les plus appréciés. Nous créons alors trois case class : pour les diamants, les couleurs tendance et le résultat final.

case class Diamant(couleur: String, prix: Int) 
case class CouleurTendance(couleur: String, scoreTendance: Int) 
case class Resultat(prix:...

Améliorer les performances algorithmiques

1. Les performances dans l’apprentissage automatique

Nous avons beaucoup parlé de performances temporelles jusqu’ici. Nous avons vu comment accélérer les traitements de Spark. À présent, intéressons-nous à une autre forme de performances : celles des algorithmes d’apprentissage automatique que nous utilisons. Pour rappel, nous avons vu qu’il y a des manières d’évaluer les méthodes que nous choisissons. Malgré tout, tout passer dans la moulinette d’évaluation peut être chronophage. C’est pourtant la seule façon de sélectionner la meilleure méthode à utiliser. Dans le monde de l’apprentissage automatique existe le concept de machine learning automatisé, ou autoML. Il s’agit de laisser la machine tester différents algorithmes sur nos données. C’est pratique pour se donner une idée de la meilleure méthode à implémenter. Une fois cela fait, il faut encore choisir les hyperparamètres à fournir. Spark ne contient pas d’outil d’autoML par défaut. Vous pouvez toutefois utiliser les algorithmes disponibles dans le framework dans une librairie externe dédiée à l’autoML. Cela vous permettra de sélectionner le plus adéquat. Ce que Spark vous propose en revanche, c’est une manière d’opter pour les meilleurs hyperparamètres. Vous pouvez en fait tester les paramètres de plusieurs éléments de votre pipeline.

Jusqu’ici, nous avons vu comment effectuer la validation en séparant nos données en deux jeux : l’un pour l’entraînement et l’autre pour l’évaluation.

2. Exemple avec validation croisée à k blocs

Voyons à présent une méthode de validation de modèle qui va un peu plus loin en nous aidant à sélectionner les hyperparamètres les plus convenables. Dans Spark, la classe CrossValidator permet de faire de la validation croisée à k blocs (k-fold cross-validation). Nous allons voir comment l’utiliser. Nous commençons par reprendre ces données :

prix

succes

51

0

45

1

50

1

55

0

44

1

Nous voulons prédire le succès...

Déboguer avec Spark

1. Vision du plan physique

a. Vision par l’intermédiaire du schéma

Au moment de déboguer, plusieurs options s’offrent à vous. Tout d’abord, le framework vous donne des logs. S’il s’agit d’une erreur de code, le message d’erreur affiché par l’outil devrait suffire. Si ce n’est pas le cas, vous devez aller plus loin. Les logs de Spark risquent de vous paraître très verbeux et peu intéressants. Vous pouvez les filtrer en vous concentrant sur les logs de type « warning » ou « error ». Utiliser l’espace de logs pour créer des informations personnalisées propres à votre application est utile. Utiliser l’espace de logs pour afficher des informations personnalisées propres à votre application (par exemple, le nombre de lignes retournées par un filtre) est utile. Mais cela est coûteux pour Spark et il faut veiller à loguer ce qui est important pour vous. Puis, pour déboguer, il y a l’interface graphique de Spark. C’est l’objet de cette section. Afin de la présenter, nous allons faire un petit programme. Nous reprenons une liste de diamants. Nous souhaitons conserver ceux dont le prix est supérieur à 50. Nous groupons par couleur et calculons le tarif moyen pour chacune. Pour simplifier, nous effectuons le travail sur une seule partition en faisant appel à la fonction coalesce.

Nous finissons par une action pour générer les transformations avec collect. Le code est le suivant :

from typing import List 
from pyspark.sql import DataFrame 
from pyspark.sql.types import StructType, StructField,  
StringType 
from pyspark.sql.functions import avg 
 
data: List = [("Diamant_1A", "TopDiamant", "300", "rouge"), 
    ("Diamant_2B", "Diamants pour toujours", "45", "jaune"), 
    ("Diamant_3C", "Mes diamants préférés", "78", "rouge"), 
    ("Diamant_4D", "Diamants que j'aime", "90", "jaune"), 
    ("Diamant_5E", "TopDiamant", "89"...

Se repérer dans la documentation

1. La documentation générale

L’entrée pour la documentation générale est à la page https://spark.apache.org/docs/latest/, qui donne accès à différents onglets.

L’onglet Overview donne un aperçu de Spark. C’est une introduction.

C’est dans l’onglet Programming Guides que vous trouverez le plus d’éléments, en particulier les informations concernant les API haut et bas niveaux.

L’onglet API Docs présente les mêmes éléments, mais sous une autre forme. Les fonctions sont classées selon le langage dans lequel elles sont écrites.

Ce sont ces deux derniers onglets qui vous serviront le plus a priori.

L’onglet Deploying correspond au déploiement de Spark, mais aussi à son intégration avec un manager de clusters. Plusieurs options sont possibles : Spark Standalone, Mesos, YARN et Kubernetes.

L’onglet More est dédié aux questions avancées de configuration, de performances et de sécurité.

2. La documentation Python

Spark a développé une documentation consacrée au langage Python. Elle est disponible à cette URL : https://spark.apache.org/docs/latest/api/python/index.html (ou par le biais de la page https://spark.apache.org/docs/latest/ via les onglets Programming Guides/Pyspark...

Déployer l’apprentissage automatique

1. Enregistrer un modèle

Dans les exemples précédents, nous avons vu que nous pouvons découvrir les structures d’un jeu de données. Puis, nous utilisons ce modèle appris sur de nouvelles lignes. Nous obtenons un objet DataFrame que nous pouvons alors sauvegarder. En réalité, il est assez rare qu’à l’entraînement succède la génération des prédictions. Plus couramment, le modèle est enregistré pour être utilisé plus tard. L’enregistrement s’opère grâce à la fonction save.

modele.save("/dbfs/mnt/data/model") 

2. Récupérer un modèle sauvegardé

Dans le dossier dans lequel le modèle a été sauvegardé, figurent deux sous-dossiers : metadata et data. Le dossier data contient des fichiers Parquet. Nous pouvons lire ces fichiers pour faire les prédictions. Pour cela, il s’agit de partir de la classe du modèle. Si nous avons entraîné un modèle avec MultilayerPerceptronClassificationModel, c’est à partir de là que nous accédons à la fonction load et à notre modèle.

modele_depuis_le_disque:  
MultilayerPerceptronClassificationModel =  
MultilayerPerceptronClassificationModel.load("/dbfs/mnt/data/model")...