Vous êtes sur la page 1sur 27

1

République Algérienne Démocratique & Populaire


Ministère de l’Enseignement Supérieur & de la Recherche Scientifique
Ecole Supérieure en Informatique 08 mai 1945 de Sidi Bel Abbes

Année universitaire : 20223-2024 Semestre 1


3 SC : ISI & SIW Module : Big Data
2

Introduction à Spark

• Apache Spark se présente comme la nouvelle génération de moteur de calcul


distribué qui remplace progressivement Hadoop/MapReduce.

• Spark permet d'écrire des traitements complexes composés de plusieurs


phases map-reduce.

• On peut le faire également avec YARN, mais les données issues de chaque
phase doivent être stockées sur HDFS, pour être réutilisées immédiatement
après dans la phase suivante. Cela prend beaucoup de temps et d'espace.

• Au contraire, Spark utilise beaucoup mieux la mémoire centrale des machines


du cluster.
3

Les composants de l’écosystème Spark

• Spark est construit autour de plusieurs modules qui permettent de répondre à


de nombreux cas d'usage de traitement de données :
4

Les composants de l’écosystème Spark : Spark Core

• C’est la base de Spark.


• Il implémente le RDD ainsi que toutes les fonctionnalités de parallélisation et
de distribution de calculs sur le cluster Spark.
• Spark Core est également responsable de la gestion de la mémoire, des
pannes, de la planification et de la surveillance des jobs sur le cluster.
• Il assure, en outre, les interactions avec les systèmes de stockage externes.
• Spark est développé en langage Scala, qui reste le langage natif et recommandé
pour développer des programmes de traitement.
• Cependant, on peut utiliser d'autres langages comme Java et Python.
5

Les composants de l’écosystème Spark

• Spark SQL : est un module qui permet d'écrire des requêtes SQL et de les
exécuter sur Spark.
• Spark Streaming : permet de traiter en temps réel des flux de données. Il
permet aux développeurs d'écrire des applications qui peuvent recevoir, traiter
et analyser en continu des données en temps réel provenant de diverses
sources.
• Spark MLlib : est un composant d'Apache Spark qui offre un framework évolutif
et distribué pour les tâches d'apprentissage automatique. Il propose une large
gamme d'algorithmes et d'utilitaires d'apprentissage automatique qui peuvent
être utilisés pour la préparation des données, l'entraînement des modèles et
l'évaluation des modèles.
• Spark GraphX : est une bibliothèque qui permet de traiter et d'analyser des
données de graphe de manière distribuée. Elle fournit des fonctionnalités pour
représenter des graphes, effectuer des calculs sur les graphes, ainsi que des
algorithmes de graphe.
6

RDD (Resilient Distributed Datasets)

• Au centre du paradigme employé par Spark, on trouve la notion de RDD.


• Le RDD est l’objet de base du traitement des données par Spark.

• Il s'agit de larges collection de données stockées en mémoire et sur lesquelles


on peut appliquer des traitements.

• Ils sont:
 Partitionnés (pour permettre à plusieurs nœuds de traiter les données).
 En lecture seule; un traitement appliqué à un RDD donne lieu à la création d'un
nouveau RDD.
7

RDD (Resilient Distributed Datasets)

 Le terme RDD renvoie les significations suivantes :


• Resilient : il est possible de reconstituer les blocs de données (partitions)
même en cas de panne lors de l'exécution du programme de traitement. C'est
cette tolérance aux pannes qui justifie le qualificatif de Résiliant.
• Distributed : les blocs de données sont distribués sur différents nœuds du
cluster Spark. Cela permet non seulement de paralléliser les opérations de
traitement mais aussi faciliter la reconstitution des blocs en cas de panne.
• Dataset : le RDD est une collection d’enregistrements de données
partitionnées.
8

Opérations sur les RDD

• Deux types d'opérations possibles sur les RDDs :


 Une transformation: une opération qui modifie les données d'un RDD. Elle
donne lieu à la création d'un nouveau RDD. Les transformations fonctionnent
en mode d'évaluation lazy: elles ne sont exécutées que quand on a
véritablement besoin d'accéder aux données.
« map » est un exemple de transformation.

 Une action : les actions accèdent aux données d'un RDD, et nécessitent donc
son évaluation (toutes les transformations ayant donné lieu à la création de ce
RDD sont exécutées l'une aprés l'autre).
« saveAsTextFile » (qui permet de sauver le contenu d'un RDD) ou « count »
(qui renvoie le nombre d'éléments dans un RDD) sont des exemples
d'actions.
9

Spark : Architecture - Exécution

• Les applications Spark s’exécutent comme un ensemble de processus


indépendants sur un cluster, coordonnés par un objet SparkContext du
programme principal, appelé Driver Program.
• Pour s’exécuter sur un cluster, le SparkContext se connecte à un Cluster
Manager.
• Une fois connecté, Spark lance des executors sur les nœuds du cluster, des
processus qui lancent des traitements et stockent les données pour les
applications.
• Il envoie ensuite le code de l’application (e.g., .jar ou ficher python) aux
executors.
10

Directed Acyclic Graph (DAG)

• Le DAG est un formalisme graphique qui permet au moteur d'exécution de


Spark de traduire l'ensemble des opérations de traitement en une séquence
d'étapes en vue de générer un plan d'exécution optimisé.
• Le DAG est généré à partir du graphe des transformations et actions sur les
RDD.
11

Directed Acyclic Graph (DAG)

• Le graphe des transformations et actions est la combinaison d'un ensemble de


sommets et d'arêtes.
• Les sommets représentent les RDD (issus des transformations) ou les résultats
(outputs) des actions.
• Les arêtes sont les transformations ou les actions qui ont permis d'obtenir les
RDD et les résultats.
• Le graphe est dit acyclique car les sommets sont reliés les uns aux autres dans
un sens unique de telle sorte qu'il est impossible d'avoir des références
circulaires.
12

Le DAG et le découpage du plan d’exécution

• Le DAG permet de structurer le plan d’exécution en plusieurs niveaux :


Task (tâche), Stage (étape) et le Job.
13

Le DAG et le découpage du plan d’exécution

• Task (Tâche): Une Tâche est une unité de traitement exécutée sur chaque partition du RDD.

• Stage (Etape) : Une Etape est une succession de pipelines de Tasks.


 Un pipeline de Tasks est un ensemble de Tasks qui s’exécutent en parallèle sur les partitions
d’un même RDD.
 Une Etape regroupe l'ensemble des opérations de transformations et d'actions qui ne
nécessitent pas de Shuffle (mélanger).
 Le Shuffle est une opération au cours de laquelle le RDD est repartitionné et redistribué sur
les nœuds de traitement Spark.
 Il nécessite le transfert des données via le réseau.
 Le Shuffle a lieu entre deux Etapes.
 Les résultats d'une première Etape sont Shufflés dans le but de calculer de nouvelles
partitions qui serviront d'inputs à Etape suivante.
 Une nouvelle étape est donc créée dans le plan d'exécution après chaque opération de
Shuffle.

• Job : un job représente l’ensemble des Stages définies dans le plan d’exécution. C’est la
matérialisation du plan d’exécution dans son ensemble.
14

Le DAG, lineage et mécanisme de reprise des tâches

• Le DAG propose des mécanismes de reprise de tâches en cas de pannes.


• Par exemple, lors de l'exécution d'une pipeline, lorsqu'une tâche est perdue à
cause d'une panne quelconque, celle-ci sera automatiquement relancée.
• La relance peut se faire sur le même nœud de traitement ou sur un autre nœud
si le premier nœud est indisponible.

• En cas de panne sévère, le DAG permet aussi de reconstituer tout un RDD en se


basant sur le Lineage.
• Le lineage est la trace de toutes les dépendances existantes entre les RDD.
• En effet, lorsqu'un nouveau RDD est dérivé d'un RDD existant à l'aide d'une
transformation, ce nouveau RDD contient un pointeur vers le RDD parent.
• Le lineage est la représentation de toutes les dépendances qui relie un RDD
avec ses RDD parents et ses RDD enfants.
15

pySpark :
implémentation de Spark en langage python.
16

Début d’un programme

• Un programme pySpark doit commencer par ceci :

from pyspark import SparkConf, SparkContext

nomappli = "essai1"
config = SparkConf().setAppName(nomappli)
##config.setMaster("spark://master:7077")
sc = SparkContext(conf=config)

• sc représente le contexte Spark. C’est un objet qui possède plusieurs méthodes


dont celles qui créent des RDD.
• La ligne commentée config.setMaster() permet de définir l’URL du Spark
Master, c’est à dire le cluster sur lequel lancer l’exécution.
17

RDD

• On peut créer un RDD de deux manières :


 Paralléliser une collection : si votre programme contient des données itérables
(tableau, liste. . . ), elles peuvent devenir un RDD.

donnees = ['v1', 'v2', 'v3', ‘v4']


RDD = sc.parallelize(donnees) #On le nomme « collection parallélisée ».

• Jeux de données externes : Spark peut utiliser de nombreuses sources de


données. Voici comment lire un simple fichier texte ou CSV :
RDD = sc.textFile("/data.txt")
18

Lire et écrire des SequenceFile

• Certains traitements Spark font appel à la notion de paires (clé,valeur).


• Les clés permettent par exemple de classer des valeurs dans un certain ordre.
• Pour stocker efficacement ce genre de RDD, on emploie un SequenceFile.
• Le SequenceFile est un type de fichier composé de paires de clé-valeur.

• Lecture d’un SequenceFile dans un RDD : cette fonction lit les paires du fichier
et crée un RDD :
RDD = sc.sequenceFile("/data1.seq")

• Écriture d’un RDD dans un SequenceFile: cette fonction enregistre les paires
(clé, valeur) du RDD :
RDD.saveAsSequenceFile("/data2.seq")
19

Actions

• Les actions sont des méthodes qui s’appliquent à un RDD pour retourner une
valeur ou une collection :
 liste = RDD.collect() retourne le RDD sous forme d’une liste Python.
 nombre = RDD.count() retourne le nombre d’éléments.
 premier = RDD.first() retourne le premier élément.
 premiers = RDD.take(n) retourne les n premiers éléments.
 Note: il n’y a pas de méthode last pour retourner le ou les derniers éléments.
 resultat = RDD.reduce(fonction) applique une fonction d’agrégation
(associative) du type fn(a,b)→c
 Exemple :

grand = RDD.reduce(lambda a,b: max(a,b))


20

Transformations de type map

 Chacune de ces méthodes retourne un nouveau RDD


• map est une méthode de la classe RDD, son seul paramètre est une lambda ou
le nom d’une fonction :
liste = sc.parallelize([1,2,3,4])
doubles = liste.map(lambda n: n*2)# doubles est un RDD contenant [2, 4, 6, 8]

• RDD.filter(fonction) : la fonction retourne un booléen. Il ne reste du RDD que


les éléments pour lesquels la fonction retourne True.
RDD = sc.parallelize([1,2,3,4])
RDD2 = RDD.filter(lambda n: (n%2)==0)
21

Transformations de type map

• RDD.flatMap(fonction) : chaque appel à la fonction doit retourner une liste


(vide ou pas) et toutes ces listes sont concaténées dans le RDD sortant.

RDD = sc.parallelize([0,1,2,3])
RDD2 = RDD.flatMap(lambda n: [n*2, n*2+1])

• La fonction lambda retourne une liste, le double et le double+1 du nombre


traité :
 Appliquée à la collection par un simple map, on obtiendrait la liste imbriquée :
[[0, 1], [2, 3], [4, 5], [6, 7]].
 Avec un flatMap, les résultats sont concaténés ensemble, donc on récupère :
[0, 1, 2, 3, 4, 5, 6, 7].
22

Transformations ensemblistes

• RDD.distinct() : retourne un seul exemplaire de chaque élément :

RDD = sc.parallelize([1, 2, 3, 4, 6, 5, 4, 3])


RDD2 = RDD.distinct()

• RDD1.union(RDD2) : contrairement à son nom, ça retourne la concaténation et


non pas l’union des deux RDD. Rajouter distinct() pour faire une vraie union.

RDD1 = sc.parallelize([1,2,3,4])
RDD2 = sc.parallelize([6,5,4,3])
print(RDD1.union(RDD2).collect())
print(RDD1.union(RDD2).distinct().collect())
23

Transformations ensemblistes

• RDD1.intersection(RDD2) : retourne l’intersection des deux RDD.

RDD1 = sc.parallelize([1,2,3,4])
RDD2 = sc.parallelize([6,5,4,3])
RDD3 = RDD1.intersection(RDD2)

• RDD1.subtract(RDD2) : retourne les éléments présents dans RDD1 et absents


dans RDD2.
RDD1 = sc.parallelize([1,2,3,4])
RDD2 = sc.parallelize([6,5,4,3])
RDD3 = RDD1.subtract(RDD2)
24

Transformations sur des paires (clé, valeur)

 Les transformations suivantes manipulent des RDD dont les éléments sont des
paires (clé, valeur) :
• RDD.groupByKey() : retourne un RDD dont les éléments sont des paires (clé,
liste des valeurs ayant cette clé dans le RDD concerné).
• RDD.sortByKey(ascending) : retourne un RDD dont les clés sont triées. Mettre
True ou False.
• RDD.reduceByKey(fonction) : regroupe les valeurs ayant la même clé et leur
applique la fonction (a,b)→c.
RDD = sc.parallelize([(1,"v1"),(2,"v2"), (1,"v3"),(2,"v4"),(1,"v5") ])
print(RDD.reduceByKey(lambda a,b: a+"-"+b).collect())

 Affiche : [(2, 'v2-v4'), (1, 'v1-v3-v5')]


25

Transformations de type jointure

 Soit RDD1={(K1,V1). . . } et RDD2={(K2,V2). . . } :


• RDD1.join(RDD2) : retourne toutes les paires (K, (V1, V2)) lorsque V1 et V2 ont
la même clé.
• RDD1.leftOuterJoin(RDD2) : retourne les paires (K, (V1, V2)) ou (K, (V1, None))
si (K,V2) manque dans RDD2.
• RDD1.rightOuterJoin(RDD2) : retourne les paires (K, (V1, V2)) ou (K, (None,
V2)) si (K,V1) manque dans RDD1
• RDD1.fullOuterJoin(RDD2) : retourne toutes les paires (K, (V1, V2)), (K, (V1,
None)) ou (K, (None, V2)).
RDD1 = sc.parallelize([ (1,"v1"),(2,"v2"),(3,"v3") ])
RDD2 = sc.parallelize([ (1,1930),(2,1961),(1,1931),(4,1974)])
print(RDD1.join(RDD2).collect())
• Affiche : [(1, ('v1', 1930)), (1, ('v1', 1931)), (2, ('v2', 1961))]
26

Bibliographie

 Akash Tandon, Sandy Ryza, Uri Laserson, Sean Owen, et Josh Wills, Advanced
Analytics with PySpark, O'REILLY, 2022
 Benjamin Renaut, Apache Spark – Présentation et architecture, Support de
Cours, 2020
 Hien Luu, Beginning Apache Spark 3, Apress, 2021
 Mark Needham et Amy E. Hodler, Graph Algorithms: Practical Examples in
Apache Spark and Neo4j, O'REILLY, 2019
 Moussa Keita, Big Data and Technologies of Storage and Processing of Massive
Data, Rapport technique, 2021
 Rudi Bruchez, Les bases de données NoSQL et le Big Data : Comprendre et
mettre en oeuvre, 2015
 Bill Chambers et Matei Zaharia, Spark : The Definitive Guide, 2018
 ….
27

Merci pour votre attention

Vous aimerez peut-être aussi