SlideShare une entreprise Scribd logo
1  sur  48
Télécharger pour lire hors ligne
APACHE SPARK
RDD : TRANSFORMATIONS, ACTIONS PAS À PAS
DR MUSTAPHA MICHRAFY
CONTACT : DATASCIENCE.KM@GMAIL.COM
CONTEXTE
Cette étude a été menée dans le cadre des
rencontres de travail organisées au
Laboratoire CERMSEM, Centre d'Économie de
la Sorbonne (CES).
2
M.MICHRAFY
PLAN
1. Contexte
2. Objectif et prérequis
3. Spark Définition et motivations
4. Positionnement de Spark dans l’eco-systeme Big Data
5. Composants de spark
6. Spark driver et workers
7. Apache Spark : vue logique et APIs
8. Vue globale sur les API Spark : dépendance et interaction
9. RDD, caractéristiques, création et Operations
10.Opérations de type transformation et action
3
M.MICHRAFY
OBJECTIF ET PRÉREQUIS
• Connaissance de l’approche objet
• Connaissance de la programmation
fonctionnelle
• Connaissance du langage Scala
Cette étude vise à mettre en pratique Spark
pas à pas. Il s’agit d’explorer les opérations
(transformations et actions) relatives à la
structure résiliente « RDD ».
PrérequisPrérequisObjectifObjectif
4
M.MICHRAFY
SPARK DÉFINITION ET MOTIVATIONS
• Framework open source dédié au calcul distribué
• Extension du design pattern map-reduce
• Différents modes de traitement : interactif et
streaming
• Exécution en mémoire
• Intervient dans le traitement de données dans un
écosystème Big-Data
• Rapide
• 10 fois plus rapide que Hadoop sur disque
• 100 fois plus rapide en mémoire que Hadoop
• Facile à développer
• Riche en terme d’opérations
• Ecriture rapide des programmes
• Mode interactif
• Code concis
• Déploiement flexible : Yarn, Standlone, Local, Mesos
• Stockage : HDFS, S3, Openstack Swift, MapR FS,
Cassandra
• Modèle de développement unifié : Batch, streaming,
interactif
• Multi-langages : Scala, Java, Python, R
Apache spark ?Apache spark ? MotivationsMotivations
5
M.MICHRAFY
POSITIONNEMENT DE SPARK DANS L’ECO-SYSTEME BIG DATA
6
Batch/ETL
processing
Spark, MapReduce, Pig, Hive
Stream
processing
Spark Streaming, Storm, Flink Streaming
Machine
Learning
Spark MLib, Mahout, Flink ML, R
Interrogation
SQL-Like
Spark SQL, Drill, Hive, Impala
Graph
processing
Spark GraphX, Giraph, GraphLab
HDFS, S3, Openstack swift, MapR FS, Cassandra
Stockage
M.MICHRAFY
COMPOSANTS DE SPARK
7
Cluster ManagerSparkContext
Spark driver
Worker Node
Executor
TaskTask
Worker Node
Executor
TaskTask
Worker Node
Executor
TaskTask
M.MICHRAFY
SPARK DRIVER ET WORKERS
8
SparkContext
Spark driver
Cluster
Manager
Local
Threads
Worker
Executor
Worker
Executor
HDFS, S3, Openstack swift, MapR FS, CassandraHDFS, S3, Openstack swift, MapR FS, Cassandra
• Un programme Spark est composé de deux programmes :
1. Le programme pilote ( driver program )
2. Les programmes travailleurs (workers program)
• Les programmes travailleurs s’exécutent soit sur les nœuds du cluster soit
sur les threads en local
• Le programme pilote interagit avec le cluster via SparkContext
• Pas de communication entre les programmes travailleurs
M.MICHRAFY
9
Spark Core
RDD (Transformations et Action)
Spark SQL Spark MLSpark
Streaming
Spark GraphX SparkR
Système de stockage
Spark supporte plusieurs systèmes de stockage
: HDFS, S3, Openstack swift, MapR FS,
Cassandra
Spark SQL est un module dédié au traitement
des données structurées avec une syntaxe
similaire à SQL. Il permet d’extraire, transformer
et charger des données sous différents formats
(CSV, JSON, Parquet, base de données) et les
exposer pour des requêtes ad-hoc.
Spark ML est une librairie
dédiée aux méthodes
d’apprentissage distribués :
Classification
Clustering
Régression
Filtrage collaboratif
Réduction de dimension
Spark Core est le moteur de calcul et
d’exécution pour la plateforme Spark :
Ordonnancement des taches
Gestion du calcul en mémoire
Recouvrement
Interaction avec le système de stockage
API RDD propose des opérations de type
transformation et Action.
Spark Streaming est dédié au traitement
temps-réel des données en flux. Il offre un
mode de traitement en micro-batch et
supportant différentes sources de données
(Kafka, Flume, Kinesis ou TCP sockets …).
Spark GraphX est dédié au traitement et à la
parallélisation de graphes. Ce module offre des
opérateurs et des algorithmes pour le
traitement des graphes. GraphX étend les RDD
de Spark via la Resilient Distributed Dataset
Graph (RDDG)
SparkR est un package R offrant une interface
légère pour utiliser Spark à partir de R. Dans
Spark 2.0.2, SparkR fournit une implémentation
de la Dataframe distribuée supportant des
opérations telles que la sélection, le filtrage,
l'agrégation. SparkR offre aussi des algorithmes
d’apprentissages distribués.
APACHE SPARK : VUE LOGIQUE ET APIS
M.MICHRAFY
VUE GLOBALE SUR LES API SPARK : DÉPENDANCE ET INTERACTION
10
Spark core
RDDRDDRDD
Spark SQL
DataframeDataframeDataframe
Spark ML
Model MLModel MLModel ML
Spark GraphX
Graph RDDGraph RDDGraph RDD
Spark Streaming
DStreamDStreamDStream
Streaming Source
File System Data Source
M.MICHRAFY
RDD, CARACTÉRISTIQUES, CRÉATION ET OPERATIONS (1)
11
1. Une RDD est une liste de partitions
2. Une RDD est associée à une liste de
dépendances avec les RDD parents
3. Une RDD dispose d’une fonction pour calculer
une partition
4. Optionnellement, un objet « partionner » pour
les RDD de type clé/valeur
5. Optionnellement, une liste indiquant
l’emplacement pour chaque partition
CaractéristiquesCaractéristiques
RDD supporte deux type d’opérations
1. Transformation
2. Action
Une transformation consiste à
appliquer une fonction sur 1 à n RDD
et à retourner une nouvelle RDD
Une action consiste à appliquer une
fonction et à retourner une valeur
OpérationsOpérations
1. Les transformations sont
paresseuses, évitant le calcul inutile.
Ceci favorise l’optimisation du
traitement.
2. Une RDD transformée est calculée
lorsqu’une action est appliquée sur
cette dernière.
Evaluation LazyEvaluation Lazy
Resilient Distributed Dataset (RDD)
Resilient : supporte la tolérance aux pannes grâce à une
modélisation du processus d’exécution par un DAG (directed
acyclic graph), et au recalcul des partitions manquantes.
Distributed : données distribuées sur les nœuds du cluster.
Dataset : collection de données partitionnée.
M.MICHRAFY
RDD, CARACTÉRISTIQUES, CRÉATION ET OPERATIONS (2)
12
Trois manières de créer une RDD
1. A partir d’une source de données
2. En parallélisant une collection via
SparkContext
3. En appliquant une opération de
type transformation sur la RDD
CréationCréation
Certaines fonctions sont disponibles
seulement sur certains types de RDD :
1. mean, variance, stdev pour les RDD
numériques
2. Join pour les RDD clé/valeur
3. L’enregistrement de fichier utilisant
des RDD basées sur des fichiers de
format séquentiel.
Pour plus de détails, voir les RDD de type
o PairRDDFunctions,
o DoubleRDDFunctions,
o SequenceFileRDDFunctions
Fonction/type RDDFonction/type RDD
In-Memory Immutable
Lazy
evaluated
Lazy
evaluated
Cacheable
Parallele
TypedPartitioned
Resilient
RDD
Spark supporte de charger ou
d’enregistrer des fichiers dans
divers formats : non structuré, semi-
structuré, structuré.
Les formats sont :
o Text
o Json
o CSV
o SequenceFile
o Protocole buffers
o Object files
Formats fichiersFormats fichiers
M.MICHRAFY
13
Opérations de type transformation et action
• Cette section présente les différentes opérations
( Transformation, Action) relatives à un type RDD.
• Elle est organisée par fiche.
• Chaque fiche porte sur une opération et contient :
1. Un objectif
2. La signature de l’opération
3. Une section « À retenir »
4. Un exemple exécuté en mode interactif (*)
(*) : Les exemple du code ont été exécutés avec spark-shell, version 2.0.2
M.MICHRAFY
OPÉRATION DE TRANSFORMATION : MÉTHODE MAP
La méthode map retourne une RDD
en appliquant une fonction passée
en argument à chaque item de la
RDD source
Il s’agit d’un design pattern
incontournable de la programmation
fonctionnelle.
ObjectifObjectif
def map[U](f: (T) ⇒ U)(implicit arg0: ClassTag[U]):
RDD[U]
API : scala, Classe : RDD,
Package : org.apache.spark
Entrée : f est une fonction : (T) => U
Sortie : une RDD de type U
SignatureSignature
// créer un RDD
val x = sc.parallelize(List( 7, 10, 12, 17, 19), 2) // x: org.apache.spark.rdd.RDD[Int] = ParallelCollectionRDD[2] at parallelize at <console>:24
// definir une fonction f
val f = (a:Int) => (a/2, a%2) // f: Int => (Int, Int) = <function1>
// définir une fonction g
val g = (a:Int) => (a*100.0)/20 // g: Int => Double = <function1>
// applique map avec f et g
val zf = x.map(f) // zf: org.apache.spark.rdd.RDD[(Int, Int)] = MapPartitionsRDD[3] at map at <console>:28
val zg = x.map(g) // zg: org.apache.spark.rdd.RDD[Double] = MapPartitionsRDD[4] at map at <console>:28
// afficher zf et zg
zf.collect() // res1: Array[(Int, Int)] = Array((3,1), (5,0), (6,0), (8,1), (9,1))
zg.collect() // res2: Array[Double] = Array(35.0, 50.0, 60.0, 85.0, 95.0)
ExempleExemple
La RDD source et la RDD retournée
ont le même nombre d’item
Si les items de la RDD source sont de
type T alors les items de la RDD
retournée sont de type f(T)
À retenirÀ retenir
14
M.MICHRAFY
OPÉRATION TERMINALE : MÉTHODE REDUCE
La méthode reduce agrège les
éléments de la RDD source en
appliquant une fonction
commutative et associative passée
en argument.
C’est une opération terminale
Il s’agit d’un design pattern
incontournable de la programmation
fonctionnelle.
ObjectifObjectif
def reduce(f: (T, T) ⇒ T): T
API : scala, Classe : RDD,
Package : org.apache.spark
Entrée : f est une fonction : (T,T) => T
Sortie : une valeur de retour de type T
SignatureSignature
// créer une RDD comportant les éléments de 1 à 10
val x = sc.parallelize(1 to 10, 3) //x: org.apache.spark.rdd.RDD[Int] = ParallelCollectionRDD[5] at parallelize at <console>:24
// définir une fonction add
val add = (_:Int, _:Int) => x$1 + x$2 // add: (Int, Int) => Int = <function2>
// calculer la somme de 1 à 10 en appliquant reduce
val s = x.reduce(add) // s: Int = 55
ExempleExemple
Soit une loi * interne sur l’ensemble
E.
La loi * est associative SSI pour tout
x,y,z de E on a : x *(y*z) = (x*y)*z
La loi * est commutative SSI pour
tout x, y de E on a : x * y = y * x
À retenirÀ retenir
15
M.MICHRAFY
OPÉRATION DE TERMINALE : MÉTHODE COUNT
La méthode count retourne le
nombre d’éléments d’une RDD
source.
C’est une opération terminale
ObjectifObjectif
def count(): Long
API : scala, Classe : RDD,
Package : org.apache.spark
Sortie : le nombre d’élements de la RRD, de type
Long
SignatureSignature
// créer une RDD comportant les éléments de 1 à 10
val x = sc.parallelize(1 to 10, 3) //x: org.apache.spark.rdd.RDD[Int] = ParallelCollectionRDD[6] at parallelize at <console>:24
val y = sc.parallelize(List((1,1), (1,2), (3,5), (3,7), (8,9), (8,13))) // y: org.apache.spark.rdd.RDD[(Int, Int)] = ParallelCollectionRDD[7] at parallelize at <console>:24
// afficher le nombre d’éléments de chaque rdd
x.count() // res3: Long = 10
y.count() // res4: Long = 6
// appel de count sans parenthèses
x.Count // res5: Long = 10
ExempleExemple
Les parenthèses ne sont pas
obligatoires lors de l’appel de
count.
Ceci relève d’une règle en scala :
pour toute méthode sans
argument, les parenthèse sont
optionnelles.
À retenirÀ retenir
16
M.MICHRAFY
OPÉRATION DE TERMINALE : MÉTHODE COUNTBYKEY
La méthode countByKey compte le
nombre de valeur par clé et retoune
une map
Cette méthode nécessite une RDD
de type (K,V)
C’est une opération terminale
ObjectifObjectif
def countByKey(): Map[K, Long]
API : scala, Classe : PairRDDFunctions,
Package : org.apache.spark
Sortie : Map[K, Long] , la valeur représente le
nombre d’éléments par clé K.
SignatureSignature
// créer une x ( chaque entier et ses diviseurs)
val x = sc.parallelize(List((10,2),(10,5), (14,2), (14,7), (30,2), (30,3), (30,5)))
//Sortie : x: org.apache.spark.rdd.RDD[(Int, Int)] = ParallelCollectionRDD[21] at parallelize at <console>:24
val r = x.countByKey()
// Sortie : r: scala.collection.Map[Int,Long] = Map(30 -> 3, 14 -> 2, 10 -> 2)
ExempleExemple
countByKey est similaire à count
countBuKey est une méthode de la
class PairRDDFunctions.
Attention, cette méthode n’est à
utiliser que si la map retounée est
de volume faible.
À retenirÀ retenir
17
M.MICHRAFY
OPÉRATION DE TERMINALE : MÉTHODE FIRST
La méthode first retourne le premier
élément de la RDD source
C’est une opération terminale
ObjectifObjectif
def first(): T
API : scala, Classe : RDD,
Package : org.apache.spark
Sortie : le premier élément de la RDD de type T
SignatureSignature
// créer une RDD comportant les éléments de 1 à 10
val x = sc.parallelize(1 to 10, 3) //x: org.apache.spark.rdd.RDD[Int] = ParallelCollectionRDD[8] at parallelize at <console>:24
val y = sc.parallelize(List((1,1), (1,2), (3,5), (3,7), (8,9))) // y: org.apache.spark.rdd.RDD[(Int, Int)] = ParallelCollectionRDD[9] at parallelize at <console>:24
val z = sc.parallelize(List())
// afficher le nombre d’éléments de chaque rdd
x.first() // res6: Int = 1
y.first() // res7: (Int, Int) = (1,1)
// Lors de cet appel, une exception se déclenche
z.first() // java.lang.ArrayStoreException: [Ljava.lang.Object;
ExempleExemple
Les parenthèses ne sont pas
obligatoires lors de l’appel de first.
Une exception se déclenche si
l’appel de first() se fait sur une RDD
source sans élément.
À retenirÀ retenir
18
M.MICHRAFY
OPÉRATION DE TERMINALE : MÉTHODE TAKE
La méthode take retourne un
tableau d’éléments, constitué des n
premiers éléments de la RDD source.
Le nombre d’éléments à retourner est
l’argument de la méthode take
C’est une opération terminale
ObjectifObjectif
def take(num: Int): Array[T]
API : scala, Classe : RDD,
Package : org.apache.spark
Entrée : num le nombre de éléments à retourner
Sortie : un tableau de type T
SignatureSignature
// créer une RDD comportant les éléments de 1 à 10
val x = sc.parallelize(1 to 10, 3) // x: org.apache.spark.rdd.RDD[Int] = ParallelCollectionRDD[10] at parallelize at <console>:24
val z = sc.parallelize(List()) // z: org.apache.spark.rdd.RDD[Nothing] = ParallelCollectionRDD[11] at parallelize at <console>:24
// appliquer la méthode take sur la rdd x
x.take(-3) // res8: Array[Int] = Array()
x.take(0) // res9: Array[Int] = Array()
x.take(2) // res10: Array[Int] = Array(1, 2)
z.take(-5) // res11: Array[Nothing] = Array()
z.take(3) // déclenche une exception
ExempleExemple
Si le num est négatif, la valeur de
retour est un tableau vide (Array())
Si num est supérieur au nombre
d’éléments de la RDD, alors tous les
éléments de RDD sont retournés.
Si la RDD est vide (sans élément),
alors l’appel à take avec une
valeur strictement positif lève une
exception
À retenirÀ retenir
19
M.MICHRAFY
OPÉRATION DE TERMINALE : MÉTHODE FLATMAP
La méthode flatMap transforme
chaque Item de la RDD source en
0 ou plusieurs items et retourne
une nouvelle RDD.
Il s’agit d’un design pattern
incontournable de la
programmation fonctionnelle.
ObjectifObjectif
def flatMap[U](f: (T) ⇒ TraversableOnce[U])(implicit
arg0: ClassTag[U]): RDD[U]
API : scala, Classe : RDD,
Package : org.apache.spark
Entrée : f est une fonction : (T) ⇒ TraversableOnce[U]
Sortie : Une RDD[U]
SignatureSignature
// créer une RDD comportant les éléments de 1 à 10
val x = sc.parallelize(List((1,2),(3,5),(8,10))
// définir une fonction f
val f = (a:Tuple2[Int,Int]) => Seq(a._1, a._2)
// appliquer flatMap sur x
Val y = x.flatMap(f)
// afficher les éléments de y
y.collect()
//Sortie : res1: Array[Int] = Array(1, 2, 3, 5, 8, 10)
ExempleExemple
flatMap est similaire à Map
La fonction f doit retourner un trait
de type TraversableOnce qui
consiste à parcourir une collection
une ou plusieurs fois.
À retenirÀ retenir
val z = parallelize(List("La meilleure facon de predire l’avenir est de le creer", "Celui qui
veut reussir trouve un moyen", "Celui qui veut rien faire trouve une excuse"))
val g = (s:String) => s.split(" ").toList
// appliquer la fonction g sur les éléments de z
val t = z.flatMap(g)
// afficher les éléments de t
t.collect()
//Sortie : res2: Array[String] = Array(La, meilleure, faþon, de, predire, l'avenir, est, de,
le, creer, Celui, qui, veut, reussir, trouve, un, moyen, Celui, qui, veut, rien, faire, trouve,
une, excuse)
1 2
20
M.MICHRAFY
OPÉRATION DE TRANSFORMATION : MÉTHODE FILTER
La méthode filter retourne une RDD
ne contenant que les items de la RDD
source satisfaisant le prédicat f , passée
en argument.
Il s’agit aussi d’un design pattern
incontournable de la programmation
fonctionnelle.
ObjectifObjectif
def filter(f: (T) ⇒ Boolean): RDD[T]
API : scala, Classe : RDD,
Package : org.apache.spark
Entrée : f est une fonction : (T) => Boolean
Sortie : une RDD de type T
SignatureSignature
// créer un RDD
val x = sc.parallelize(List( 7, 10, 12, 17, 19), 2) // x: org.apache.spark.rdd.RDD[Int] = ParallelCollectionRDD[0] at parallelize at <console>:24
// definir une fonction f
val f = (a:Int) => (a%2==0) // f: Int => Boolean = <function1>
// définir une fonction g
Val g = (a:Int) => (a>50) // g: Int => Boolean = <function1>
// applique filter avec f et g
val zf = x.map(f) // zf: org.apache.spark.rdd.RDD[Boolean] = MapPartitionsRDD[1] at map at <console>:28
val zg = x.map(g) // zg: org.apache.spark.rdd.RDD[Boolean] = MapPartitionsRDD[2] at map at <console>:28
// afficher zf et zg
zf.collect() // res0: Array[Boolean] = Array(false, true, true, false, false)
Zg.collect() // res2: Array[Boolean] = Array(false, false, false, false, false)
ExempleExemple
La RDD source et la RDD obtenue
ont le même type d’item (T)
Le nombre d’éléments de la RDD
obtenue est toujours inférieur au
nombre d’éléments de la RDD
source
Il est possible d’obtenir une RDD
sans item.
À retenirÀ retenir
21
M.MICHRAFY
OPÉRATION DE TRANSFORMATION : MÉTHODE SAMPLE
La méthode sample retourne un
échantillon des données – qui est une
sélection aléatoire- de la RDD
source.
ObjectifObjectif
def sample(withRpl: Boolean, fraction: Double,
seed: Long = Utils.random.nextLong): RDD[T]
API : scala, Classe : RDD, Package : org.apache.spark
Entrée : withRpl : avec ou sans répétition
fraction : le % des données, dans [0 1]
seed : pour initialiser le générateur aléatoire
Sortie : une RDD de type T
SignatureSignature
// créer un RDD de 100 entiers
val x = sc.parallelize(1 to 100, 2) // x: org.apache.spark.rdd.RDD[Int] = ParallelCollectionRDD[3] at parallelize at <console>:24
// Faire une selection aléatoire d’un % de 0,1
val smpl1 = x.sample(true, 0.1, 7) // smpl1: org.apache.spark.rdd.RDD[Int] = PartitionwiseSampledRDD[4] at sample at <console>:26
smpl1.collect() // res3: Array[Int] = Array(3, 6, 14, 47, 48, 72, 78, 84, 87, 92, 100)
// Faire une selection aléatoire d’un % de 0,3
val smpl2 = x.sample(false, 0.3, 17) // smpl2: org.apache.spark.rdd.RDD[Int] = PartitionwiseSampledRDD[6] at sample at <console>:26
smpl2.collect() // res5: Array[Int] = Array(3, 4, 8, 11, 12, 14, 16, 18, 19, 21, 23, 25, 30, 33, 36, 37, 38, 42, 43, 46, 47, 49, 55,
// 58, 61, 64, 69, 70, 73, 74, 76, 80, 86, 89, 96)
ExempleExemple
Si withRpl = true, on utilise un
générateur basé sur la loi de
Poisson
Si withRpl = false, on utilise un
générateur basé sur la loi de
Bernoulli.
À retenirÀ retenir
22
M.MICHRAFY
OPÉRATION DE TRANSFORMATION: MÉTHODE TAKESAMPLE
La méthode takeSample retourne un
tableau – qui est une sélection
aléatoire- de la RDD source.
Le nombre d’éléments du tableau est
un argument de la méthode
takeSample
ObjectifObjectif
def takeSample(withReplacement: Boolean, num:
Int, seed: Long = Utils.random.nextLong): Array[T]
API : scala, Classe : RDD, Package : org.apache.spark
Entrée : withRpl : avec ou sans répitition
num : le nombre d’éléments à retourner
seed : pour initialiser le générateur aléatoire
Sortie : un tableau de type T (Array[T])
SignatureSignature
// créer un RDD de 100 entiers
val x = sc.parallelize(1 to 100, 2) // x: org.apache.spark.rdd.RDD[Int] = ParallelCollectionRDD[7] at parallelize at <console>:24
val smpl1take = x.takeSample(true, 10, 7) // smpl1take: Array[Int] = Array(19, 29, 64, 52, 74, 87, 93, 46, 27, 31)
val smpl2take = x.takeSample(false, 10, 7) // smpl2take: Array[Int] = Array(41, 80, 72, 24, 90, 100, 56, 87, 50, 78)
ExempleExemple
Cette méthode retourne
exactement un tableau
composé de num éléments de la
RDD source.
Elle est différente de la méthode
sample puisque sample prend un
argument fraction indiquant le %
d’éléments à retourner et
retourne une RDD.
À retenirÀ retenir
23
M.MICHRAFY
OPÉRATION TERMINALE: MÉTHODE TAKEORDERED
La méthode takeOrdered ordonne
les éléments de données du RDD en
utilisant l’ordre implicite (croissant) et
renvoie les n premiers éléments sous
forme d’un tableau.
ObjectifObjectif
def takeOrdered(num: Int)(implicit ord:
Ordering[T]): Array[T]
API : scala, Classe : RDD, Package : org.apache.spark
Entrée :
num: le nombre d’éléments à retourner
Sortie : un tableau de type T (array[T])
SignatureSignature
sc.parallelize(Seq(6, 8, 9, 1, 2, 3)).takeOrdered(3) // res1: Array[Int] = Array(1, 2, 3)
sc.parallelize(Seq(0, 6, 8, 9, 1, 2, 3)).takeOrdered(3) // res2: Array[Int] = Array(0, 1, 2)
sc.parallelize(Seq((1,2),(1,4),(6,7), (9,11), (8,1))).takeOrdered(3) // res3: Array[(Int, Int)] = Array((1,2), (1,4), (6,7))
sc.parallelize(Seq(("aa",2),("bc",4),("ef",7), ("aa",11), ("ef",1))).takeOrdered(3) // res4: Array[(String, Int)] = Array((aa,2), (aa,11), (bc,4))
ExempleExemple
Cette méthode est à ne pas
utiliser lorsque le tableau retourné
est volumineux car les données
sont chargées sur la mémoire du
driver.
Les éléments de la RDD source
doivent disposer d’une relation
d’ordre
À retenirÀ retenir
24
M.MICHRAFY
OPÉRATION TERMINALE : MÉTHODE FOLD
Agréger les données en deux étapes. Il
s’agit d’une opération de type Action.
L’étape 1 consiste à appliquer op par
partition
L’étape 2 consiste appliquer op sur les
résultats de la 1 étape
op doit être un opérateur associatif
ObjectifsObjectifs
def fold(zeroValue: T)(op: (T, T) ⇒ T): T
API : scala, Classe : rdd, Package : org.apache.spark
Entrée :
- zeroValue : de type T, c est la valeur initiale de calcul
- op est une fonction associative de signature : (T,T) => T
Sortie : une valeur de type T
SignatureSignature
val x = sc.parallelize( 1 to 6, 2) // x: org.apache.spark.rdd.RDD[Int] = ParallelCollectionRDD[0] at parallelize at <console>:24
// calculer la somme de éléments de x via les partitions
val op = (a:Int,b:Int) => a+b // op: (Int, Int) => Int = <function2>
// zeroValue : 0
x.fold(0)((op) // res10: Int = 21
ExempleExemple
Fold et agrgregate sont
similaires en terme de
processus
fold applique le même
fonction en 1 et 2 étape
Aggregate associe une
fonction à chaque étape
À retenirÀ retenir
25
M.MICHRAFY
OPÉRATION DE TRANSFORMATION : MÉTHODE MAPPARTITIONSWITHINDEX
Calculer une nouvelle RDD en
appliquant une fonction f sur chaque
partition
il nécessite au moins un paramètre
de type fonction qui prend en entrée
les éléments d’une partition et son
index
ObjectifsObjectifs
def mapPartitionsWithIndex[U](f: (Int, Iterator[T]) ⇒ Iterator[U],
ind: Boolean = false)(implicit arg0: ClassTag[U]): RDD[U]
API : scala, Classe : rdd, Package : org.apache.spark
Entrée :
- f est une fonction (Int, Iterator[T]) ⇒ Iterator[U]
- ind est boolean, dont la valeur par défaut est false,
Sortie : RDD[U]
SignatureSignature
// définir un RDD ( 1 …10) avec 3 partitions
val x = sc.parallelize(1 to 10, 3) // x: org.apache.spark.rdd.RDD[Int] = ParallelCollectionRDD[12] at parallelize at <console>:24
// affiche une liste de tuple, chaque tuple est composé de l'index de la partition et la valeur de l'élément.
def f[T](i:Int, p:Iterator[T]) : Iterator[(Int,T)] = p.map(w => (i,w)) // f: [T](i: Int, p: Iterator[T])Iterator[(Int, T)]
val y = x.mapPartitionsWithIndex(f) // y: org.apache.spark.rdd.RDD[(Int, Int)] = MapPartitionsRDD[13] at mapPartitionsWithIndex at
<console>:28
y.collect() // res8: Array[(Int, Int)] = Array((0,1), (0,2), (0,3), (1,4), (1,5), (1,6), (2,7), (2,8), (2,9), (2,10))
ExempleExemple
Il est similaire à map
map applique une fonction sur
les éléments de la RDD alors
que mapPartitionsWithIndex
applique une fonction f à
chaque partition
À retenirÀ retenir
26
M.MICHRAFY
OPÉRATION TERMINALE : MÉTHODE AGGREGATE
Agréger les données en deux étapes. Il
s’agit d’une opération de type Action
L’étape 1 consiste à appliquer seqOp par
partition
L’étape 2 consiste à appliquer combOp
aux résultats de l’étape 1
ObjectifsObjectifs
def aggregate[U](zeroValue: U)(seqOp: (U, T) ⇒ U,
combOp: (U, U) ⇒ U)(implicit arg0: ClassTag[U]): U
API : scala, Classe : rdd, Package : org.apache.spark
Entrée
- zeroValue : la valeur initiale de l’accumulateur de type U
- seqOp : c’est une fonction associative qui sera appliquée sur chaque partition
- comOp : c’est une fonction associative qui s’applique sur les résulats données par seqOp.
Sortie : une valeur de retour de type U
SignatureSignature
val x = sc.parallelize( 1 to 6, 2) // x: org.apache.spark.rdd.RDD[Int] = ParallelCollectionRDD[0] at parallelize at <console>:24
// calculer la somme de éléments de x via les partitions
val seqOp = (a:Int,b:Int) => if(a>b) a else b // seqOp: (Int, Int) => Int = <function2>
val compOp = (a:Int,b:Int) => a + b // compOp: (Int, Int) => Int = <function2>
// affiche une liste de tuple, chaque tuple est composé de l'index de la partition et la valeur de l'élément.
def f[T](i:Int, p:Iterator[T]) : Iterator[(Int,T)] = p.map(w => (i,w)) // f: [T](i: Int, p: Iterator[T])Iterator[(Int, T)]
// afficher chaque élément et sa partition
x.mapPartitionsWithIndex(f).collect() // res4: Array[(Int, Int)] = Array((0,1), (0,2), (0,3), (1,4), (1,5), (1,6), (2,7), (2,8), (2,9), (2,10))
// appliquer la méthode aggregate sur la RDD X
x.aggregate(0)( seqOp, compOp) // res10: Int = 19
ExempleExemple
27
M.MICHRAFY
OPÉRATION DE TRANSFORMATION : MÉTHODE MAPVALUES
La méthode mapValues, s’applique à
une RDD de type (K,V) et retourne une
RDD de type (K,U).
Cette méthode prend en argument
une fonction f: (V) ⇒ U, et transforme
chaque pair (K,V) en (K, f(U)).
C’est une opération de transformation
ObjectifObjectif
def mapValues[U](f: (V) ⇒ U): RDD[(K, U)]
API : scala, Classe : PairRDDFunctions,
Package : org.apache.spark
Sortie : RDD[(K, U)]
SignatureSignature
// créer une RDD constitué d’une liste de fruits
val x = sc.parallelize(List("Abricot", "Cerise", "Nectarine", "Noisette", "Kiwi"))
x: org.apache.spark.rdd.RDD[String] = ParallelCollectionRDD[31] at parallelize
at <console>:24
// créer une RDD de type (K,V), avec V = la taille de K
val y = x.map(w => (w,w.length))
y// : org.apache.spark.rdd.RDD[(String, Int)] = MapPartitionsRDD[30] at map
at <console>:26
// /afficher la RDD y
y.collect() // res1: Array[(String, Int)] = Array((Abricot,7), (Cerise,6),
(Nectarine,9), (Raisin,6), (Kiwi,4))
// créer une fonction f
val f = (n:Int) => (n/2, n%2) // f: Int => (Int, Int) = <function1>
ExempleExemple
La RDD source et la RDD obtenue
ont :
• La même taille.
• Les mêmes clés
• Les mêmes partitions
À retenirÀ retenir
28
// appliquer mapValues sur y avec la fonction f
val z = y.mapValues(f)
//Sortie : z: org.apache.spark.rdd.RDD[(String, (Int, Int))] =
MapPartitionsRDD[33] at mapValues at // <console>:30
// afficher le résultat
z.collect()
res2: Array[(String, (Int, Int))] = Array((Abricot,(3,1)), (Cerise,(3,0)),
(Nectarine,(4,1)), (Noisette,(4,0)), (Kiwi,(2,0)))
y.Count == z.count
res49: Boolean = true
1 2
M.MICHRAFY
OPÉRATION TERMINALE : MÉTHODE COLLECT
La méthode collect retourne un tableau (
Array) qui représente les éléments de la
RDD.
Il est utile lors de la mise au point d’un
code.
ObjectifsObjectifs
def collect(): Array[T]
API : scala, Classe : rdd, Package : org.apache.spark
Sortie : Array[T]
SignatureSignature
// définir un RDD ( 1 …10) avec 2 partitions
val x = sc.parallelize(1 to 10, 2) // x: org.apache.spark.rdd.RDD[Int] = ParallelCollectionRDD[14] at parallelize at <console>:24
// appliquer la méthode collect pour obtenir un tableau
val x_arr = x.collect() // x_arr: Array[Int] = Array(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)
// Appel sans parenthèse
x.Collect // res0: Array[Int] = Array(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)
ExempleExemple
Cette méthode est couteuse
en terme de CPU. Par
conséquent, elle est à utiliser
seulement si la RDD a un faible
volume.
À retenirÀ retenir
29
M.MICHRAFY
OPÉRATION TERMINALE : MÉTHODE FOREACH
La méthode foreach applique une
fonction f (T) => Unit, sur chaque élément
de la RDD
Il est utile lors de la mise au point d’un
code.
ObjectifsObjectifs
def foreach(f: (T) ⇒ Unit): Unit
API : scala, Classe : rdd, Package : org.apache.spark
Entrée :
f une fonction ( (T) => Unit)
Sortie : pas de valeur de retour (Unit)
SignatureSignature
// définir des RDD
val x = sc.parallelize(1 to 5, 2) // x: org.apache.spark.rdd.RDD[Int] = ParallelCollectionRDD[15] at parallelize at <console>:24
val y = sc.parallelize(List("Banane", "Kiwi", "Cerise", "Orange", "Fraise"),2)
val z = y.zip(x) // z: org.apache.spark.rdd.RDD[(String, Int)] = ZippedPartitionsRDD2[17] at zip at <console>:28
// afficher les éléments de la RDD x
x.foreach(w => print(w + ", ")) // 1, 3, 4, 5, 2,
// afficher les éléments de la RDD y
y.foreach(w => print(w + ", ")) // Cerise, Orange, Banane, Fraise, Kiwi,
// afficher les éléments de la RDD z
z.foreach(w => print(w + ", ")) // (Banane,1), (Cerise,3), (Orange,4), (Kiwi,2), (Fraise,5),
Exemple
Attention, foreach n’affiche
pas forcement la même chose
que la méthode collect
À retenirÀ retenir
30
M.MICHRAFY
OPÉRATION DE TRANSFORMATION : MÉTHODE COLLECT AVEC DES ARGUMENTS
Elle retourne une RDD comportant les
éléments correspondant à
l'application d’une fonction partielle
Cette méthode est couteuse en
terme de CPU. Par conséquent, elle
est à utiliser seulement si la RDD a un
faible volume.
ObjectifsObjectifs
collect[U](f: PartialFunction[T, U])(implicit arg0:
ClassTag[U]): RDD[U]
API : scala, Classe : rdd, Package : org.apache.spark
Sortie : Array[T]
SignatureSignature
// créer une rdd avec des éléments de 1 à 10
val sample = sc.parallelize(1 to 10) // sample: org.apache.spark.rdd.RDD[Int] = ParallelCollectionRDD[18] at parallelize at <console>:24
// Déclarer une fonction partielle
val isEven: PartialFunction[Int,Int] = { case x if x % 2 == 0 => x } // isEven: PartialFunction[Int,Int] = <function1>
// appel de la méthode collect avec l’argument isEven (la fonction partielle)
val sample_fp = sample.collect(isEven) // sample_fp: org.apache.spark.rdd.RDD[Int] = MapPartitionsRDD[22] at collect at <console>:30
// afficher les élements de la rdd sample_fp
sample_fp.collect() // res11: Array[Int] = Array(2, 4, 6, 8, 10)
ExempleExemple
Elle est similaire à la méthode
collect sans argument.
collect() retourne un tableau
alors que collect(PartialFunction)
retourne une RDD [U] après avoir
appliqué la fonction partielle sur
les items de la RDD.
À retenirÀ retenir
31
M.MICHRAFY
OPÉRATION DE TRANSFORMATION : MÉTHODE DISTINCT
La méthode distinct retourne une
RDD qui comporte les éléments
distincts de la RDD source
ObjectifsObjectifs
def distinct(): RDD[T]
API : scala, Classe : rdd, Package : org.apache.spark
Sortie : RDD[T]
SignatureSignature
// créer un rdd avec les éléments : 1,1,2,3,4,5,5
val z = sc.parallelize(List(1,1,2,3,4,5,5)) // z: org.apache.spark.rdd.RDD[Int] = ParallelCollectionRDD[23] at parallelize at <console>:24
// appliquer la méthode distinct sur la rdd z
val zsd = z.distinct() // zsd: org.apache.spark.rdd.RDD[Int] = MapPartitionsRDD[26] at distinct at <console>:26
// regrouper le resultat dans un tableau
zsd.collect() // res12: Array[Int] = Array(4, 1, 5, 2, 3)
val l = List(List(1,2),List(3,4), List(4,3), List(1,2), List(1,2,3,4)) // l: List[List[Int]] = List(List(1, 2), List(3, 4), List(4, 3), List(1, 2), List(1, 2, 3, 4))
val zobj = sc.parallelize(l) // zobj: org.apache.spark.rdd.RDD[List[Int]] = ParallelCollectionRDD[27] at parallelize at <console>:26
// observer le resultat
val zobjsd = zobj.distinct() // zobjsd: org.apache.spark.rdd.RDD[List[Int]] = MapPartitionsRDD[30] at distinct at <console>:28
zobjsd.collect() // res14: Array[List[Int]] = Array(List(3, 4), List(1, 2, 3, 4), List(4, 3), List(1, 2))
ExempleExemple
Il est possible de mettre en
place la méthode distinct en
utilisant :
• map
• reduceByKey
À retenirÀ retenir
32
M.MICHRAFY
OPÉRATION DE TRANSFORMATION : MÉTHODE UNION
La méthode union retourne une RDD
qui est l’union des items de la RDD
source et de la RDD passée en
argument.
il est possible d’avoir des éléments
identiques dans la RDD résultat. Pour
éviter cela, utiliser la méthode distinct
ObjectifsObjectifs
def union(other: RDD[T]): RDD[T]
API : scala, Classe : rdd, Package : org.apache.spark
Entrée : other est de type RDD[T].
Sortie : RDD[T]
SignatureSignature
// créer les rdd avec les éléments : 1 to 10, et 5 to 15
val x = sc.parallelize(1 to 10) // x: org.apache.spark.rdd.RDD[Int] = ParallelCollectionRDD[31] at parallelize at <console>:24
val y = sc.parallelize(5 to 15) // y: org.apache.spark.rdd.RDD[Int] = ParallelCollectionRDD[32] at parallelize at <console>:24
// appliquer la méthode union
val uad = x.union(y) // uad: org.apache.spark.rdd.RDD[Int] = UnionRDD[33] at union at <console>:28
// appliquer la méthode union et supprimer les éléments identiques
val usd = x.union(y).distinct() // usd: org.apache.spark.rdd.RDD[Int] = MapPartitionsRDD[37] at distinct at <console>:28
// afficher les résultats
uad.collect() // res15: Array[Int] = Array(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15)
usd.collect() // res16: Array[Int] = Array(8, 1, 9, 10, 2, 11, 3, 4, 12, 13, 5, 14, 6, 15, 7)
ExempleExemple
Les éléments de la RDD source
et la rdd other doivent être de
même type (ici T)
Plus précisément, les éléments
de la RDD other doivent être de
même type que ceux de la rdd
source.
À retenirÀ retenir
33
M.MICHRAFY
OPÉRATION DE TRANSFORMATION : MÉTHODE INTERSECTION
La méthode intersection retourne une
RDD qui est l’intersection des items du
RDD source et de la RDD passée en
argument.
Attention, le résultat de retour ne
comporte pas de doublant même si
la RDD source ou argument en
comporte.
ObjectifsObjectifs
def intersection(other: RDD[T]): RDD[T]
API : scala, Classe : rdd, Package : org.apache.spark
Entrée : other est de type RDD[T].
Sortie : RDD[T]
SignatureSignature
// créer deux rdds
val x = sc.parallelize(List(1 , 1, 2, 3, 4, 7)) // x: org.apache.spark.rdd.RDD[Int] = ParallelCollectionRDD[38] at parallelize at <console>:24
val y = = sc.parallelize(List(1, 1, 4, 4, 5, 6)) // y: org.apache.spark.rdd.RDD[Int] = ParallelCollectionRDD[39] at parallelize at <console>:24
// appliquer la méthode intersection
val z = x. intersection(y) // z: org.apache.spark.rdd.RDD[Int] = MapPartitionsRDD[45] at intersection at <console>:28
// afficher les résultats
z.collect() // res17: Array[Int] = Array(4, 1)
ExempleExemple
Les éléments de la RDD other
doivent être de même type que
ceux de la rdd source.
intersection peut être codée
avec :
• map,
• cogroup
• filter
À retenirÀ retenir
34
M.MICHRAFY
OPÉRATION DE TRANSFORMATION : MÉTHODE SUBTRACT
La méthode subtract est
l’implémentation de l’opération
soustraction au sens ensemble.
Elle retourne les éléments de la RDD
source mais qui ne sont pas dans la
RDD passée en argument.
ObjectifsObjectifs
def subtract(other: RDD[T]): RDD[T]
API : scala, Classe : rdd, Package : org.apache.spark
Entrée : other est de type RDD[T]
Sortie : RDD[T]
SignatureSignature
// créer les 2 rdds
val x = sc.parallelize(1 to 5, 2)
val y = sc.parallelize(3 to 7, 2)
x.collect() // res18: Array[Int] = Array(1, 2, 3, 4, 5)
y.collect() // res19: Array[Int] = Array(3, 4, 5, 6, 7)
// appliquer la méthode subtract et generer la RDD s
val s = x.subtract(y)
// afficher les éléments
s.collect() // res20: Array[Int] = Array(2, 1)
ExempleExemple
La RDD other doit être de même
type que la RDD source. Dans le
cas contraire, on obtient une
erreur.
Il existe des variante de subtract
portant sur le nombre des
partitions.
À retenirÀ retenir
// créer une RDD
val z = sc.parallelize(List("A","B","D","E"),2)
// appliquer la méthode subtract sur x et z
// cette instruction génère une erreur
val t = x.subtract(z)
error: type mismatch;
found : org.apache.spark.rdd.RDD[String]
required: org.apache.spark.rdd.RDD[Int]
val t = x.subtract(z)
1 2
35
M.MICHRAFY
OPÉRATION DE TRANSFORMATION : MÉTHODE ZIP
La méthode zip consiste à construire
une RDD de type (K,V) à partir de la
RDD[K] source et la RDD[V] passée en
argument.
L’élément i de la RDD résultante est
(ki,vi) avec ki, vi les éléments d’indice i
resp. des RDD source et argument.
ObjectifsObjectifs
def zip[U](other: RDD[U])(implicit arg0: ClassTag[U]): RDD[(T, U)]
API : scala, Classe : rdd, Package : org.apache.spark
Entrée : other est de type RDD[U].
Sortie : un RDD de type (T,U)
SignatureSignature
// créer les deux rdds
val key = sc.parallelize(1 to 5, 2)
val value = sc.parallelize(11 to 15, 2 )
// appliquer la méthode zip
val x = key.zip(value)
// afficher les éléments
x.collect()
// res21: Array[(Int, Int)] = Array((1,11), (2,12), (3,13), (4,14), (5,15))
Exemple 1Exemple 1
Pour réaliser une opération zip,
les deux RDD doivent avoir :
• Le même nombre de
partitions
• Le même nombre
d'éléments dans chaque
Partition
À retenirÀ retenir
// créer deux rdds
val value_nes = sc.parallelize(11 to 16, 2 )
val value_nps = sc.parallelize(11 to 15, 3 )
// appliquer la méthode zip
val x_nes = key.zip(value_nes)
val x_nps = key.zip(value_nep)
// Des exceptions se lèvent lors de l’appel de collect
X_nex.collect() // error : Can only zip RDDs with same number of elements in each partition
x_nep.collect() // error : Can't zip RDDs with unequal numbers of partitions
Exemple 2Exemple 2
36
M.MICHRAFY
OPÉRATION DE TRANSFORMATION : MÉTHODE GROUPBY
La méthode groupBy regroupe les
éléments de la RDD[T] source par clé
et retourne une RDD [(k, Iterable[T])]
Elle prend en entrée une fonction f :
(T) => K, qui s’applique à chaque
élément de la RDD source pour
générer les clés de la RDD retournée.
ObjectifObjectif
def groupBy[K](f: (T) ⇒ K)(implicit kt:
ClassTag[K]): RDD[(K, Iterable[T])]
API : scala, Classe : RDD
Package : org.apache.spark
Sortie : RDD[(K, Iterable[T])]
SignatureSignature
// créer la rdd de type (Int) avec 10 partitions
val x = sc.parallelize(1 to 20, 10)
// faire une selection aléatoire dans les éléments de x
val y = x.sample(false, 0.1, 19)
// definir la function f
val f = (w:Int) => w%3 // f: Int => Int = <function1>
// définir une fonction g
val g = (w:Int) => 2*w + 7 // g: Int => Int = <function1>
ExempleExemple
Cette méthode est très couteuse.
Il existe deux variantes de cette méthode,
prenant en plus soit le nombre de partitions, soit
un partitionner
Attention la RDD est de type (K, Iterable[T])],
sachant que f : (T) => K
Elle est similaire avec la méthode groupByKey
À retenirÀ retenir
// appliquer la groupBy , avec f, sur les éléments de y
val z = y.groupBy(f)
// appliquer groupBy, avec g, sur les éléments de y
val s = y.groupBy(g)
// afficher z et s
z.collect() // res25: Array[(Int, Iterable[Int])] = Array((0,CompactBuffer(6, 15)))
s.collect() // res26: Array[(Int, Iterable[Int])] = Array((37,CompactBuffer(15)), (19,CompactBuffer(6)))
1 2
37
M.MICHRAFY
OPÉRATION DE TRANSFORMATION : MÉTHODE GROUPBYKEY
Pour une RDD de type (K, V),
groupByKey retourne une RDD de
type (K,Iterable<V>)
Si le regroupement vise une
agrégation, pour des raisons de
performance, il est conseillé d’utiliser
reduceByKey ou aggregateByKey.
ObjectifObjectif
def groupByKey(): RDD[(K, Iterable[V])]
API : scala,
Classe : PairRDDFunctions,
Package : org.apache.spark
Sortie : RDD[(K, Iterable[V])]
SignatureSignature
// créer la rdd de type (k,v) avec deux partitions
val x = sc.parallelize(List((1,1),(11,2),(11,6),(2,8),(3,5),(3,7)),2) // x: org.apache.spark.rdd.RDD[(Int, Int)] = ParallelCollectionRDD[67] at parallelize at <console>:24
// appliquer la méthode groupeByKey pour regrouper par clé
val z = x.groupByKey() // z: org.apache.spark.rdd.RDD[(Int, Iterable[Int])] = ShuffledRDD[68] at groupByKey at <console>:26
// afficher les données de la RDD z
z.collect() // res27: Array[(Int, Iterable[Int])] = Array((2,CompactBuffer(8)), (11,CompactBuffer(2, 6)), (1,CompactBuffer(1)), (3,CompactBuffer(5, 7)))
ExempleExemple
groupByKey est une méthode de la classe
PairRDDFunctions. Elle s’applique à des RDD de type
(k,v).
groupByKey utilise un partitionner par défaut
Il existe différente variante de cette méthode :
- def groupByKey(numPartitions: Int): RDD[(K, Iterable[V])]
- def groupByKey(partitioner: Partitioner): RDD[(K, Iterable[V])]
À retenirÀ retenir
38
M.MICHRAFY
OPÉRATION DE TRANSFORMATION : MÉTHODE REDUCEBYKEY
Pour une RDD de type (k,v),
reduceByKey retourne une RDD de
type (k,v) où les valeurs de chaque
clé sont agrégées en utilisant la
fonction f de type (v,v) => v.
ObjectifObjectif
def reduceByKey(func: (V, V) ⇒ V): RDD[(K, V)]
API : scala, Classe : PairRDDFunctions, Package :
org.apache.spark
Entrée : une fonction associative, commutative de type (v,v) => v
Sortie RDD[(K, V)]
SignatureSignature
// créer la rdd de type (k,v) avec deux partitions
val t = Seq((1,1),(1,8), (2,7), (2,9), (3,13), (3, 10))
val x = sc.parallelize(t, 2) // // x: org.apache.spark.rdd.RDD[(Int, Int)] = ParallelCollectionRDD[4] at parallelize at <console>:24
// créer la fonction func
val func = (x:Int, y:Int) => x + y // func: (Int, Int) => Int = <function2>
// appliquer la méthode reduceByKey pour regrouper par clé et appliquer func
val y = x.reduceByKey(func) // y: org.apache.spark.rdd.RDD[(Int, Int)] = ShuffledRDD[5] at reduceByKey at <console>:32
x.collect() // // res2: Array[(Int, Int)] = Array((1,1), (1,8), (2,7), (2,9), (3,13), (3,10))
// afficher les résultats
y.collect() // res3: Array[(Int, Int)] = Array((2,16), (1,9), (3,23))
ExempleExemple
reduceByKey estune méthode
de la classe PairRDDFunctions.
il existe deux variantes de cette
méthode nécessitant en plus soit
le nombre de partitions soit un
partitionner.
À retenirÀ retenir
39
M.MICHRAFY
OPÉRATION DE TRANSFORMATION : MÉTHODE AGGREGATEBYKEY
Pour une RDD[(k,v)], aggregateByKey
retourne une RDD[(k,u)] où les valeurs
de chaque clé sont agrégées en
appliquant les fonctions seqOp et
combOp et la valeur neutre
zeroValue.
Elle est similaire à aggregate sauf
que l'agrégation est appliquée aux
valeurs ayant la même clé
ObjectifObjectif
def aggregateByKey[U](zero: U)(seqOp: (U, V) ⇒ U,
combOp: (U, U) ⇒ U)(implicit arg0: ClassTag[U]):
RDD[(K, U)]
API : scala, Classe : PairRDDFunctions,
Package : org.apache.spark
Entrée : zero valeur neutre de type U
seqOp : (U,V) => U et CombOp : (U,U) => U
Sortie : RDD[(K, V)]
SignatureSignature
// créer la rdd de type (k,v) avec deux partitions
val x = sc.parallelize(List(("Bannane", 4),("Fraise", 1),("Bannane", 3),("Kiwi", 2),("Fraise", 2),("Orange", 5),("Orange",6),("Raisin",4)),2)
// Pour chaque élément de la RDD x, afficher sa partition et sa valeur
x.mapPartitionsWithIndex((i,p) => p.map(w => (i,w))).collect()
// res28: Array[(Int, (String, Int))] = Array((0,(Bannane,4)), (0,(Fraise,1)), (0,(Bannane,3)), (0,(Kiwi,2)), (1,(Fraise,2)), (1,(Orange,5)), (1,(Orange,6)), (1,(Raisin,4)))
// créer deux fonctions seqOp et combOp
val seqOp = (a:Int, b:Int) => Math.max(a,b) // seqOp: (Int, Int) => Int = <function2>
val combOp = (a:Int, b:Int) => a + b // combOp: (Int, Int) => Int = <function2>
// appliquer la méthode aggregateByKey
val y = x.aggregateByKey(0)(seqOp, combOp) // y: org.apache.spark.rdd.RDD[(String, Int)] = ShuffledRDD[76] at aggregateByKey at <console>:30
// afficher les résultats
y.collect() // res29: Array[(String, Int)] = Array((Raisin,4), (Kiwi,2), (Fraise,3), (Orange,6), (Bannane,4))
ExempleExemple
aggregateByKey est une
méthode de la classe
PairRDDFunctions.
il existe deux variantes de cette
méthode nécessitant en plus
soit le nombre de partitions soit
un partitionner.
À retenirÀ retenir
40
M.MICHRAFY
OPÉRATION DE TRANSFORMATION : MÉTHODE SORTBYKEY
Pour une RDD[(k,v)], sortByKey
retourne une RDD[(k,v)] triée selon un
ordre prédéfini
La clé doit implémenter le trait
Ordered
ObjectifObjectif
def sortByKey(ascending: Boolean = true,
numPartitions: Int = self.partitions.length): RDD[(K, V)]
API : scala, Classe : OrderedRDDFunctions,
Package : org.apache.spark
Entrée : ascending boolean indiquant le type de trie
numPartitions, optionnel, indique le nombre
de partitions
Sortie : RDD[(K, V)]
SignatureSignature
// créer une rdd de type (k,v)
val x = sc.parallelize(List(("B", 4),("K", 2),("F", 2),("O", 5),("R",4)),3)
// appliquer la méthode sortByKey
val yas = x.sortByKey(true)
val yde = x.sortByKey(false)
// afficher les résultats
yas.collect() // res30: Array[(String, Int)] = Array((B,4), (F,2), (K,2), (O,5), (R,4))
yde.collect() // res32: Array[(String, Int)] = Array((R,4), (O,5), (K,2), (F,2), (B,4))
Exemple 1Exemple 1
sortByKey est une méthode de
la classe OrderedRDDFunctions.
Par conséquent, la RDD source
doit avoir des élements de type
(K,V)
À retenirÀ retenir
case class A(tag:String, load:Int) extends Ordered[A] {
def compare( a:A ) = tag.compareTo(a.tag)
}
// créer une rdd de type (k,v)
val xls = List( A("w",50), A("v",2), A("l",7), A("s",6))
val xlsrdd = sc.parallelize(xls,2)
val v = sc.parallelize(1 to 4,2)
val xx = xlsrdd.zip(v)
// appliquer la méthode sortByKey
val yy = xx.sortByKey(true)
// afficher les résultats
yy.collect() // Array[(A, Int)] = Array((A(l,7),3), (A(s,6),4), (A(v,2),2), (A(w,50),1))
Exemple 2Exemple 2
41
M.MICHRAFY
OPÉRATION DE TRANSFORMATION : MÉTHODE JOIN
La méthode join nécessite des RDD
de type (K,V)
Elle permet de faire une jointure sur la
clé entre la RDD source et la RDD
passée en argument.
La valeur de retour est une RDD de
type (K, (V, W))
ObjectifObjectif
def join[W](other: RDD[(K, W)]): RDD[(K, (V, W))]
API : scala, Classe : PairRDDFunctions,
Package : org.apache.spark
Entrée : other est une RDD de type (K,W)
Sortie : RDD[(K, (V, W))]
SignatureSignature
// créer des rdd de type (k,v)
val l1 = List(("A",1),("B",2),("C",3),("D",5),("E",1))
Val l2 = List(("A",2),("E",2),("C",5),("D",5),("G",1))
val x = sc.parallelize(l1,2) //x: org.apache.spark.rdd.RDD[(String, Int)] = ParallelCollectionRDD[7] at parallelize at <console>:26
val y = sc.parallelize(l2, 2) // y: org.apache.spark.rdd.RDD[(String, Int)] = ParallelCollectionRDD[8] at parallelize at <console>:26
// appliquer la méthode join // z: org.apache.spark.rdd.RDD[(String, (Int, Int))] = MapPartitionsRDD[11] at join at <console>:32
val z = x.join(y)
// afficher les résultats
z.collect() // res1: Array[(String, (Int, Int))] = Array((D,(5,5)), (A,(1,2)), (C,(3,5)), (E,(1,2)))
il existe deux variantes de cette
méthode nécessitant en plus
soit le nombre de partitions soit
un partitionner.
il existe aussi une jointure à
droite ou à gauche
( voir leftOuterJoin, rightOuterJoin)
À retenirÀ retenir
ExempleExemple
42
M.MICHRAFY
OPÉRATION DE TRANSFORMATION : MÉTHODE CARTESIAN
La méthode cartesian retourne une
RDD[(K,V)] qui est le produit cartésien
de la RDD source et la RDD
argument.
La RDD retournée est de taille nxm
avec n, m les nombres d’éléments de
la RDD source et la RDD passée en
argument.
ObjectifObjectif
def cartesian[U](other: RDD[U])(implicit arg0:
ClassTag[U]): RDD[(T, U)]
API : scala, Classe : RDD,
Package : org.apache.spark
Entrée : other est une RDD de type U
Sortie : une RDD de type (T,U)
SignatureSignature
// créer deux RDD
val x = sc.parallelize( 1 to 5, 2) // x: org.apache.spark.rdd.RDD[Int] = ParallelCollectionRDD[12] at parallelize at <console>:24
val y = sc.parallelize(List(("A",2),("E",2),("C",5)), 2) // y: org.apache.spark.rdd.RDD[(String, Int)] = ParallelCollectionRDD[13] at parallelize at <console>:24
// calculer le produit cartésien de x et y
val z = x. cartesian(y) // z: org.apache.spark.rdd.RDD[(Int, (String, Int))] = CartesianRDD[14] at cartesian at <console>:28
// évaluer la taille de z // res3: Boolean = true
z.count() == x.count () * y.count()
// afficher les éléments de z // res4: Array[(Int, (String, Int))] = Array((1,(A,2)), (2,(A,2)), (1,(E,2)), (1,(C,5)), (2,(E,2)), (2,(C,5)), (3,(A,2)),
z.collect() // (4,(A,2)), (5,(A,2)), (3,(E,2)), (3,(C,5)), (4,(E,2)), (4,(C,5)), (5,(E,2)), (5,(C,5)))
ExempleExemple
La RDD retournée est une
instance de la classe
PairRDDFunctions,
Pour un élément (k,v) de la RDD
retournée, k est un élément de la
RDD source et v est un élément
de la RDD passée en argument
À retenirÀ retenir
43
M.MICHRAFY
OPÉRATION DE TRANSFORMATION : MÉTHODE COGROUP
Pour une RDD source (K,V) et une
RDD de type (K,W), la méthode
cogroup retourne une RDD de
type (K, (Iterable<V>,
Iterable<W>)).
ObjectifObjectif
def cogroup[W](other: RDD[(K, W)]): RDD[(K,
(Iterable[V], Iterable[W]))]
API : scala, Classe : PairRDDFunctions,
Package : org.apache.spark
Entrée : other est une RDD de type (K,W)
Sortie : une RDD de type [(K, (Iterable[V],
Iterable[W]))
SignatureSignature
// créer deux RDD de type clé-valeur
val x = sc.parallelize(List(("A",1), ("A",2),("C",5), ("D",10),("D",1)), 2)
val y = sc.parallelize(List(("A",3), ("B",3), ("B",6), ,("C",7)), 2)
// regrouper par clé
val z = x. cogroup(y) // RDD[(String, (Iterable[Int], Iterable[Int]))] = MapPartitionsRDD[18] at cogroup at <console>:28
// comparer le nombre des clés distinct avec celui du nombre d’éléments de z
x.map(w => w._1).union(y.map(w => w._1)).distinct().count() == z.count() // res5: Boolean = true
// calculer le nombre des éléments de z
z.count() // res6: Long = 4
// afficher les éléments de z
z.collect() // res7: Array[(String, (Iterable[Int], Iterable[Int]))] = Array((B,(CompactBuffer(),CompactBuffer(3, 6))), (D,(CompactBuffer(10,1),CompactBuffer())),
// (A,(CompactBuffer(1, 2),CompactBuffer(3))), (C,(CompactBuffer(5),CompactBuffer(7))))
Cette méthode a plusieurs variantes :
2 à 3 arguments de type RDD[(K,W)]
Le nombre de partitions
Le nombre d’éléments de la RDD
obtenue est égal au nombre de clés
distinctes dans les deux RDD.
SI une clé est absente d’une RDD alors sa
valeur est remplacé par vide.
À retenirÀ retenir
ExempleExemple
44
M.MICHRAFY
OPÉRATION DE TRANSFORMATION : MÉTHODE COALESCE
La méthode coalesce
regroupe les données de la
RDD source dans un nombre
de données de partitions.
ObjectifObjectif
def coalesce(numPartitions: Int, shuffle: Boolean = false,
partitionCoalescer: Option[PartitionCoalescer] =
Option.empty)(implicit ord: Ordering[T] = null): RDD[T]
API : scala, Classe : RDD, Package : org.apache.spark
Entrée : numPartitions le nombre de partitions visé
shuffle pour l’étape de shuffle, par défaut false
partitionCoalescer optionnel, indique la manière de
fusionner les partitions
Sortie : une RDD de type T
SignatureSignature
// créer une RDD avec 50 partitions
val x = sc.parallelize( 1 to 1000, 50) // x: org.apache.spark.rdd.RDD[Int] = ParallelCollectionRDD[25] at parallelize at <console>:24
// appliquer coalesce
val y = x. coalesce(10, true) // y: org.apache.spark.rdd.RDD[Int] = MapPartitionsRDD[29] at coalesce at <console>:26
val z = x.coalesce(3, false) // z: org.apache.spark.rdd.RDD[Int] = CoalescedRDD[30] at coalesce at <console>:26
// afficher les partitions
y. getNumPartitions // res8: Int = 10
z. getNumPartitions // res9: Int = 3
ExempleExemple
La méthode coalesce est
similaire à la méthode
repartition
Elle permet de contrôler le
nombre de partitions d’ une
RDD
À retenirÀ retenir
45
M.MICHRAFY
OPÉRATION DE TRANSFORMATION : MÉTHODE REPARTITION
La méthode repartition
regroupe les données de la
RDD source dans un nombre
donné de partitions.
ObjectifObjectif
def repartition(numPartitions: Int)(implicit ord: Ordering[T] =
null): RDD[T]
API : scala, Classe : RDD, Package : org.apache.spark
Entrée : numPartitions le nombre de partitions visé
Sortie : une RDD de type T
SignatureSignature
// créer une RDD avec 50 partitions
val x = sc.parallelize( 1 to 1000, 50) // x: org.apache.spark.rdd.RDD[Int] = ParallelCollectionRDD[31] at parallelize at <console>:24
// appliquer repartition
val y = x. repartition(10) // y: org.apache.spark.rdd.RDD[Int] = MapPartitionsRDD[35] at repartition at <console>:26
// afficher le nombre de partitions
y. getNumPartitions // res10: Int = 10
ExempleExemple
La méthode repartition
est similaire à la méthode
coalesce.
Cette méthode fait appel à
la méthode coalesce avec
les deux arguments :
numPartitions et shuffle=true
À retenirÀ retenir
46
M.MICHRAFY
OPÉRATION DE TRANSFORMATION : MÉTHODE SAVEASTEXTFILE
La méthode saveAsTextFile
enregistre le contenu de la
RDD dans le dossier passé en
argument
ObjectifObjectif
def saveAsTextFile(path: String): Unit
API : scala, Classe : RDD, Package : org.apache.spark
Entrée : path le nom fichier
Sortie : pas de valeur de retour (Unit).
SignatureSignature
// créer une RDD avec 50 partitions
val x = sc.parallelize( 1 to 20, 3)
val y = sc.parallelize(List((1,2),(3,5),(6,7),(8,10),(11,15),(18,20)), 2)
// enregistrer les données de la RDD x dans rdd_x
x.saveAsTextFile("rdd_x") // un dossier rdd_x est crée avec des fichiers contenant les données de chaque partition
// enregistrer les données de la RDD y dans rdd_x
y.saveAsTextFile("rdd_x") // Une exception se déclenche puisque le dossier rdd_x existe
ExempleExemple
saveAsTextFile crée un
dossier path et enregistre les
données de chaque partition
dans un fichier part-0000x où
x est un entier.
Si le dossier path existe alors
une exception se déclenche.
À retenirÀ retenir
47
M.MICHRAFY
DR MUSTAPHA MICHRAFY
CONTACT : DATASCIENCE.KM@GMAIL.COM

Contenu connexe

Tendances

Tendances (20)

Big Data, Hadoop & Spark
Big Data, Hadoop & SparkBig Data, Hadoop & Spark
Big Data, Hadoop & Spark
 
BigData_Chp1: Introduction à la Big Data
BigData_Chp1: Introduction à la Big DataBigData_Chp1: Introduction à la Big Data
BigData_Chp1: Introduction à la Big Data
 
Cours Big Data Chap1
Cours Big Data Chap1Cours Big Data Chap1
Cours Big Data Chap1
 
Cours Big Data Chap5
Cours Big Data Chap5Cours Big Data Chap5
Cours Big Data Chap5
 
Cours Big Data Chap2
Cours Big Data Chap2Cours Big Data Chap2
Cours Big Data Chap2
 
BigData_TP1: Initiation à Hadoop et Map-Reduce
BigData_TP1: Initiation à Hadoop et Map-ReduceBigData_TP1: Initiation à Hadoop et Map-Reduce
BigData_TP1: Initiation à Hadoop et Map-Reduce
 
Big data
Big dataBig data
Big data
 
Technologies pour le Big Data
Technologies pour le Big DataTechnologies pour le Big Data
Technologies pour le Big Data
 
Cours Big Data Chap3
Cours Big Data Chap3Cours Big Data Chap3
Cours Big Data Chap3
 
Apache Kafka, Un système distribué de messagerie hautement performant
Apache Kafka, Un système distribué de messagerie hautement performantApache Kafka, Un système distribué de messagerie hautement performant
Apache Kafka, Un système distribué de messagerie hautement performant
 
introduction à MongoDB
introduction à MongoDBintroduction à MongoDB
introduction à MongoDB
 
Une introduction à Hive
Une introduction à HiveUne introduction à Hive
Une introduction à Hive
 
Traitement distribue en BIg Data - KAFKA Broker and Kafka Streams
Traitement distribue en BIg Data - KAFKA Broker and Kafka StreamsTraitement distribue en BIg Data - KAFKA Broker and Kafka Streams
Traitement distribue en BIg Data - KAFKA Broker and Kafka Streams
 
Hive ppt (1)
Hive ppt (1)Hive ppt (1)
Hive ppt (1)
 
TP1 Big Data - MapReduce
TP1 Big Data - MapReduceTP1 Big Data - MapReduce
TP1 Big Data - MapReduce
 
BigData_Chp5: Putting it all together
BigData_Chp5: Putting it all togetherBigData_Chp5: Putting it all together
BigData_Chp5: Putting it all together
 
BigData_TP2: Design Patterns dans Hadoop
BigData_TP2: Design Patterns dans HadoopBigData_TP2: Design Patterns dans Hadoop
BigData_TP2: Design Patterns dans Hadoop
 
Hadoop Hbase - Introduction
Hadoop Hbase - IntroductionHadoop Hbase - Introduction
Hadoop Hbase - Introduction
 
Cours Big Data Chap6
Cours Big Data Chap6Cours Big Data Chap6
Cours Big Data Chap6
 
Les BD NoSQL
Les BD NoSQLLes BD NoSQL
Les BD NoSQL
 

Similaire à Spark RDD : Transformations & Actions

Similaire à Spark RDD : Transformations & Actions (20)

Spark
SparkSpark
Spark
 
Spark - An In-Memory Distributed Computing Engine.pptx
Spark - An In-Memory Distributed Computing Engine.pptxSpark - An In-Memory Distributed Computing Engine.pptx
Spark - An In-Memory Distributed Computing Engine.pptx
 
spark_intro_1208
spark_intro_1208spark_intro_1208
spark_intro_1208
 
Introduction Apche Spark
Introduction Apche SparkIntroduction Apche Spark
Introduction Apche Spark
 
Spark SQL principes et fonctions
Spark SQL principes et fonctionsSpark SQL principes et fonctions
Spark SQL principes et fonctions
 
Distributed computing with Spark 2.x
Distributed computing with Spark 2.xDistributed computing with Spark 2.x
Distributed computing with Spark 2.x
 
Spark - Ippevent 19-02-2015
Spark - Ippevent 19-02-2015Spark - Ippevent 19-02-2015
Spark - Ippevent 19-02-2015
 
Presentation intis 2017 version27112017
Presentation intis 2017 version27112017Presentation intis 2017 version27112017
Presentation intis 2017 version27112017
 
Elastic serach
Elastic serachElastic serach
Elastic serach
 
Introduction spark
Introduction sparkIntroduction spark
Introduction spark
 
Spark - Alexis Seigneurin (Français)
Spark - Alexis Seigneurin (Français)Spark - Alexis Seigneurin (Français)
Spark - Alexis Seigneurin (Français)
 
Syllabus advanced big data with spark
Syllabus advanced big data with sparkSyllabus advanced big data with spark
Syllabus advanced big data with spark
 
Zenika matinale spark-zeppelin_ml
Zenika matinale spark-zeppelin_mlZenika matinale spark-zeppelin_ml
Zenika matinale spark-zeppelin_ml
 
Tech day hadoop, Spark
Tech day hadoop, SparkTech day hadoop, Spark
Tech day hadoop, Spark
 
Techday Arrow Group: Hadoop & le Big Data
Techday Arrow Group: Hadoop & le Big DataTechday Arrow Group: Hadoop & le Big Data
Techday Arrow Group: Hadoop & le Big Data
 
code4lib 2011 : choses vues et entendues par l'ABES
code4lib 2011 : choses vues et entendues par l'ABEScode4lib 2011 : choses vues et entendues par l'ABES
code4lib 2011 : choses vues et entendues par l'ABES
 
Spark, ou comment traiter des données à la vitesse de l'éclair
Spark, ou comment traiter des données à la vitesse de l'éclairSpark, ou comment traiter des données à la vitesse de l'éclair
Spark, ou comment traiter des données à la vitesse de l'éclair
 
Les bases pour utiliser SPARQL
Les bases pour utiliser SPARQLLes bases pour utiliser SPARQL
Les bases pour utiliser SPARQL
 
Spark-adabra, Comment Construire un DATALAKE ! (Devoxx 2017)
Spark-adabra, Comment Construire un DATALAKE ! (Devoxx 2017) Spark-adabra, Comment Construire un DATALAKE ! (Devoxx 2017)
Spark-adabra, Comment Construire un DATALAKE ! (Devoxx 2017)
 
P8 03 presentation
P8 03 presentationP8 03 presentation
P8 03 presentation
 

Plus de MICHRAFY MUSTAFA

Plus de MICHRAFY MUSTAFA (8)

Daily scrum
Daily scrumDaily scrum
Daily scrum
 
Evenements scrum
Evenements scrumEvenements scrum
Evenements scrum
 
Scrum 2020 : concepts et principes
Scrum 2020 : concepts et principesScrum 2020 : concepts et principes
Scrum 2020 : concepts et principes
 
Base de données graphe, Noe4j concepts et mise en oeuvre
Base de données graphe, Noe4j concepts et mise en oeuvreBase de données graphe, Noe4j concepts et mise en oeuvre
Base de données graphe, Noe4j concepts et mise en oeuvre
 
Apache SPARK ML : principes, concepts et mise en œuvre
Apache SPARK  ML : principes, concepts et  mise en œuvre Apache SPARK  ML : principes, concepts et  mise en œuvre
Apache SPARK ML : principes, concepts et mise en œuvre
 
Scala: Pattern matching, Concepts and Implementations
Scala: Pattern matching, Concepts and ImplementationsScala: Pattern matching, Concepts and Implementations
Scala: Pattern matching, Concepts and Implementations
 
Scala : programmation fonctionnelle
Scala : programmation fonctionnelleScala : programmation fonctionnelle
Scala : programmation fonctionnelle
 
Interface fonctionnelle, Lambda expression, méthode par défaut, référence de...
Interface fonctionnelle, Lambda expression, méthode par défaut,  référence de...Interface fonctionnelle, Lambda expression, méthode par défaut,  référence de...
Interface fonctionnelle, Lambda expression, méthode par défaut, référence de...
 

Spark RDD : Transformations & Actions

  • 1. APACHE SPARK RDD : TRANSFORMATIONS, ACTIONS PAS À PAS DR MUSTAPHA MICHRAFY CONTACT : DATASCIENCE.KM@GMAIL.COM
  • 2. CONTEXTE Cette étude a été menée dans le cadre des rencontres de travail organisées au Laboratoire CERMSEM, Centre d'Économie de la Sorbonne (CES). 2 M.MICHRAFY
  • 3. PLAN 1. Contexte 2. Objectif et prérequis 3. Spark Définition et motivations 4. Positionnement de Spark dans l’eco-systeme Big Data 5. Composants de spark 6. Spark driver et workers 7. Apache Spark : vue logique et APIs 8. Vue globale sur les API Spark : dépendance et interaction 9. RDD, caractéristiques, création et Operations 10.Opérations de type transformation et action 3 M.MICHRAFY
  • 4. OBJECTIF ET PRÉREQUIS • Connaissance de l’approche objet • Connaissance de la programmation fonctionnelle • Connaissance du langage Scala Cette étude vise à mettre en pratique Spark pas à pas. Il s’agit d’explorer les opérations (transformations et actions) relatives à la structure résiliente « RDD ». PrérequisPrérequisObjectifObjectif 4 M.MICHRAFY
  • 5. SPARK DÉFINITION ET MOTIVATIONS • Framework open source dédié au calcul distribué • Extension du design pattern map-reduce • Différents modes de traitement : interactif et streaming • Exécution en mémoire • Intervient dans le traitement de données dans un écosystème Big-Data • Rapide • 10 fois plus rapide que Hadoop sur disque • 100 fois plus rapide en mémoire que Hadoop • Facile à développer • Riche en terme d’opérations • Ecriture rapide des programmes • Mode interactif • Code concis • Déploiement flexible : Yarn, Standlone, Local, Mesos • Stockage : HDFS, S3, Openstack Swift, MapR FS, Cassandra • Modèle de développement unifié : Batch, streaming, interactif • Multi-langages : Scala, Java, Python, R Apache spark ?Apache spark ? MotivationsMotivations 5 M.MICHRAFY
  • 6. POSITIONNEMENT DE SPARK DANS L’ECO-SYSTEME BIG DATA 6 Batch/ETL processing Spark, MapReduce, Pig, Hive Stream processing Spark Streaming, Storm, Flink Streaming Machine Learning Spark MLib, Mahout, Flink ML, R Interrogation SQL-Like Spark SQL, Drill, Hive, Impala Graph processing Spark GraphX, Giraph, GraphLab HDFS, S3, Openstack swift, MapR FS, Cassandra Stockage M.MICHRAFY
  • 7. COMPOSANTS DE SPARK 7 Cluster ManagerSparkContext Spark driver Worker Node Executor TaskTask Worker Node Executor TaskTask Worker Node Executor TaskTask M.MICHRAFY
  • 8. SPARK DRIVER ET WORKERS 8 SparkContext Spark driver Cluster Manager Local Threads Worker Executor Worker Executor HDFS, S3, Openstack swift, MapR FS, CassandraHDFS, S3, Openstack swift, MapR FS, Cassandra • Un programme Spark est composé de deux programmes : 1. Le programme pilote ( driver program ) 2. Les programmes travailleurs (workers program) • Les programmes travailleurs s’exécutent soit sur les nœuds du cluster soit sur les threads en local • Le programme pilote interagit avec le cluster via SparkContext • Pas de communication entre les programmes travailleurs M.MICHRAFY
  • 9. 9 Spark Core RDD (Transformations et Action) Spark SQL Spark MLSpark Streaming Spark GraphX SparkR Système de stockage Spark supporte plusieurs systèmes de stockage : HDFS, S3, Openstack swift, MapR FS, Cassandra Spark SQL est un module dédié au traitement des données structurées avec une syntaxe similaire à SQL. Il permet d’extraire, transformer et charger des données sous différents formats (CSV, JSON, Parquet, base de données) et les exposer pour des requêtes ad-hoc. Spark ML est une librairie dédiée aux méthodes d’apprentissage distribués : Classification Clustering Régression Filtrage collaboratif Réduction de dimension Spark Core est le moteur de calcul et d’exécution pour la plateforme Spark : Ordonnancement des taches Gestion du calcul en mémoire Recouvrement Interaction avec le système de stockage API RDD propose des opérations de type transformation et Action. Spark Streaming est dédié au traitement temps-réel des données en flux. Il offre un mode de traitement en micro-batch et supportant différentes sources de données (Kafka, Flume, Kinesis ou TCP sockets …). Spark GraphX est dédié au traitement et à la parallélisation de graphes. Ce module offre des opérateurs et des algorithmes pour le traitement des graphes. GraphX étend les RDD de Spark via la Resilient Distributed Dataset Graph (RDDG) SparkR est un package R offrant une interface légère pour utiliser Spark à partir de R. Dans Spark 2.0.2, SparkR fournit une implémentation de la Dataframe distribuée supportant des opérations telles que la sélection, le filtrage, l'agrégation. SparkR offre aussi des algorithmes d’apprentissages distribués. APACHE SPARK : VUE LOGIQUE ET APIS M.MICHRAFY
  • 10. VUE GLOBALE SUR LES API SPARK : DÉPENDANCE ET INTERACTION 10 Spark core RDDRDDRDD Spark SQL DataframeDataframeDataframe Spark ML Model MLModel MLModel ML Spark GraphX Graph RDDGraph RDDGraph RDD Spark Streaming DStreamDStreamDStream Streaming Source File System Data Source M.MICHRAFY
  • 11. RDD, CARACTÉRISTIQUES, CRÉATION ET OPERATIONS (1) 11 1. Une RDD est une liste de partitions 2. Une RDD est associée à une liste de dépendances avec les RDD parents 3. Une RDD dispose d’une fonction pour calculer une partition 4. Optionnellement, un objet « partionner » pour les RDD de type clé/valeur 5. Optionnellement, une liste indiquant l’emplacement pour chaque partition CaractéristiquesCaractéristiques RDD supporte deux type d’opérations 1. Transformation 2. Action Une transformation consiste à appliquer une fonction sur 1 à n RDD et à retourner une nouvelle RDD Une action consiste à appliquer une fonction et à retourner une valeur OpérationsOpérations 1. Les transformations sont paresseuses, évitant le calcul inutile. Ceci favorise l’optimisation du traitement. 2. Une RDD transformée est calculée lorsqu’une action est appliquée sur cette dernière. Evaluation LazyEvaluation Lazy Resilient Distributed Dataset (RDD) Resilient : supporte la tolérance aux pannes grâce à une modélisation du processus d’exécution par un DAG (directed acyclic graph), et au recalcul des partitions manquantes. Distributed : données distribuées sur les nœuds du cluster. Dataset : collection de données partitionnée. M.MICHRAFY
  • 12. RDD, CARACTÉRISTIQUES, CRÉATION ET OPERATIONS (2) 12 Trois manières de créer une RDD 1. A partir d’une source de données 2. En parallélisant une collection via SparkContext 3. En appliquant une opération de type transformation sur la RDD CréationCréation Certaines fonctions sont disponibles seulement sur certains types de RDD : 1. mean, variance, stdev pour les RDD numériques 2. Join pour les RDD clé/valeur 3. L’enregistrement de fichier utilisant des RDD basées sur des fichiers de format séquentiel. Pour plus de détails, voir les RDD de type o PairRDDFunctions, o DoubleRDDFunctions, o SequenceFileRDDFunctions Fonction/type RDDFonction/type RDD In-Memory Immutable Lazy evaluated Lazy evaluated Cacheable Parallele TypedPartitioned Resilient RDD Spark supporte de charger ou d’enregistrer des fichiers dans divers formats : non structuré, semi- structuré, structuré. Les formats sont : o Text o Json o CSV o SequenceFile o Protocole buffers o Object files Formats fichiersFormats fichiers M.MICHRAFY
  • 13. 13 Opérations de type transformation et action • Cette section présente les différentes opérations ( Transformation, Action) relatives à un type RDD. • Elle est organisée par fiche. • Chaque fiche porte sur une opération et contient : 1. Un objectif 2. La signature de l’opération 3. Une section « À retenir » 4. Un exemple exécuté en mode interactif (*) (*) : Les exemple du code ont été exécutés avec spark-shell, version 2.0.2 M.MICHRAFY
  • 14. OPÉRATION DE TRANSFORMATION : MÉTHODE MAP La méthode map retourne une RDD en appliquant une fonction passée en argument à chaque item de la RDD source Il s’agit d’un design pattern incontournable de la programmation fonctionnelle. ObjectifObjectif def map[U](f: (T) ⇒ U)(implicit arg0: ClassTag[U]): RDD[U] API : scala, Classe : RDD, Package : org.apache.spark Entrée : f est une fonction : (T) => U Sortie : une RDD de type U SignatureSignature // créer un RDD val x = sc.parallelize(List( 7, 10, 12, 17, 19), 2) // x: org.apache.spark.rdd.RDD[Int] = ParallelCollectionRDD[2] at parallelize at <console>:24 // definir une fonction f val f = (a:Int) => (a/2, a%2) // f: Int => (Int, Int) = <function1> // définir une fonction g val g = (a:Int) => (a*100.0)/20 // g: Int => Double = <function1> // applique map avec f et g val zf = x.map(f) // zf: org.apache.spark.rdd.RDD[(Int, Int)] = MapPartitionsRDD[3] at map at <console>:28 val zg = x.map(g) // zg: org.apache.spark.rdd.RDD[Double] = MapPartitionsRDD[4] at map at <console>:28 // afficher zf et zg zf.collect() // res1: Array[(Int, Int)] = Array((3,1), (5,0), (6,0), (8,1), (9,1)) zg.collect() // res2: Array[Double] = Array(35.0, 50.0, 60.0, 85.0, 95.0) ExempleExemple La RDD source et la RDD retournée ont le même nombre d’item Si les items de la RDD source sont de type T alors les items de la RDD retournée sont de type f(T) À retenirÀ retenir 14 M.MICHRAFY
  • 15. OPÉRATION TERMINALE : MÉTHODE REDUCE La méthode reduce agrège les éléments de la RDD source en appliquant une fonction commutative et associative passée en argument. C’est une opération terminale Il s’agit d’un design pattern incontournable de la programmation fonctionnelle. ObjectifObjectif def reduce(f: (T, T) ⇒ T): T API : scala, Classe : RDD, Package : org.apache.spark Entrée : f est une fonction : (T,T) => T Sortie : une valeur de retour de type T SignatureSignature // créer une RDD comportant les éléments de 1 à 10 val x = sc.parallelize(1 to 10, 3) //x: org.apache.spark.rdd.RDD[Int] = ParallelCollectionRDD[5] at parallelize at <console>:24 // définir une fonction add val add = (_:Int, _:Int) => x$1 + x$2 // add: (Int, Int) => Int = <function2> // calculer la somme de 1 à 10 en appliquant reduce val s = x.reduce(add) // s: Int = 55 ExempleExemple Soit une loi * interne sur l’ensemble E. La loi * est associative SSI pour tout x,y,z de E on a : x *(y*z) = (x*y)*z La loi * est commutative SSI pour tout x, y de E on a : x * y = y * x À retenirÀ retenir 15 M.MICHRAFY
  • 16. OPÉRATION DE TERMINALE : MÉTHODE COUNT La méthode count retourne le nombre d’éléments d’une RDD source. C’est une opération terminale ObjectifObjectif def count(): Long API : scala, Classe : RDD, Package : org.apache.spark Sortie : le nombre d’élements de la RRD, de type Long SignatureSignature // créer une RDD comportant les éléments de 1 à 10 val x = sc.parallelize(1 to 10, 3) //x: org.apache.spark.rdd.RDD[Int] = ParallelCollectionRDD[6] at parallelize at <console>:24 val y = sc.parallelize(List((1,1), (1,2), (3,5), (3,7), (8,9), (8,13))) // y: org.apache.spark.rdd.RDD[(Int, Int)] = ParallelCollectionRDD[7] at parallelize at <console>:24 // afficher le nombre d’éléments de chaque rdd x.count() // res3: Long = 10 y.count() // res4: Long = 6 // appel de count sans parenthèses x.Count // res5: Long = 10 ExempleExemple Les parenthèses ne sont pas obligatoires lors de l’appel de count. Ceci relève d’une règle en scala : pour toute méthode sans argument, les parenthèse sont optionnelles. À retenirÀ retenir 16 M.MICHRAFY
  • 17. OPÉRATION DE TERMINALE : MÉTHODE COUNTBYKEY La méthode countByKey compte le nombre de valeur par clé et retoune une map Cette méthode nécessite une RDD de type (K,V) C’est une opération terminale ObjectifObjectif def countByKey(): Map[K, Long] API : scala, Classe : PairRDDFunctions, Package : org.apache.spark Sortie : Map[K, Long] , la valeur représente le nombre d’éléments par clé K. SignatureSignature // créer une x ( chaque entier et ses diviseurs) val x = sc.parallelize(List((10,2),(10,5), (14,2), (14,7), (30,2), (30,3), (30,5))) //Sortie : x: org.apache.spark.rdd.RDD[(Int, Int)] = ParallelCollectionRDD[21] at parallelize at <console>:24 val r = x.countByKey() // Sortie : r: scala.collection.Map[Int,Long] = Map(30 -> 3, 14 -> 2, 10 -> 2) ExempleExemple countByKey est similaire à count countBuKey est une méthode de la class PairRDDFunctions. Attention, cette méthode n’est à utiliser que si la map retounée est de volume faible. À retenirÀ retenir 17 M.MICHRAFY
  • 18. OPÉRATION DE TERMINALE : MÉTHODE FIRST La méthode first retourne le premier élément de la RDD source C’est une opération terminale ObjectifObjectif def first(): T API : scala, Classe : RDD, Package : org.apache.spark Sortie : le premier élément de la RDD de type T SignatureSignature // créer une RDD comportant les éléments de 1 à 10 val x = sc.parallelize(1 to 10, 3) //x: org.apache.spark.rdd.RDD[Int] = ParallelCollectionRDD[8] at parallelize at <console>:24 val y = sc.parallelize(List((1,1), (1,2), (3,5), (3,7), (8,9))) // y: org.apache.spark.rdd.RDD[(Int, Int)] = ParallelCollectionRDD[9] at parallelize at <console>:24 val z = sc.parallelize(List()) // afficher le nombre d’éléments de chaque rdd x.first() // res6: Int = 1 y.first() // res7: (Int, Int) = (1,1) // Lors de cet appel, une exception se déclenche z.first() // java.lang.ArrayStoreException: [Ljava.lang.Object; ExempleExemple Les parenthèses ne sont pas obligatoires lors de l’appel de first. Une exception se déclenche si l’appel de first() se fait sur une RDD source sans élément. À retenirÀ retenir 18 M.MICHRAFY
  • 19. OPÉRATION DE TERMINALE : MÉTHODE TAKE La méthode take retourne un tableau d’éléments, constitué des n premiers éléments de la RDD source. Le nombre d’éléments à retourner est l’argument de la méthode take C’est une opération terminale ObjectifObjectif def take(num: Int): Array[T] API : scala, Classe : RDD, Package : org.apache.spark Entrée : num le nombre de éléments à retourner Sortie : un tableau de type T SignatureSignature // créer une RDD comportant les éléments de 1 à 10 val x = sc.parallelize(1 to 10, 3) // x: org.apache.spark.rdd.RDD[Int] = ParallelCollectionRDD[10] at parallelize at <console>:24 val z = sc.parallelize(List()) // z: org.apache.spark.rdd.RDD[Nothing] = ParallelCollectionRDD[11] at parallelize at <console>:24 // appliquer la méthode take sur la rdd x x.take(-3) // res8: Array[Int] = Array() x.take(0) // res9: Array[Int] = Array() x.take(2) // res10: Array[Int] = Array(1, 2) z.take(-5) // res11: Array[Nothing] = Array() z.take(3) // déclenche une exception ExempleExemple Si le num est négatif, la valeur de retour est un tableau vide (Array()) Si num est supérieur au nombre d’éléments de la RDD, alors tous les éléments de RDD sont retournés. Si la RDD est vide (sans élément), alors l’appel à take avec une valeur strictement positif lève une exception À retenirÀ retenir 19 M.MICHRAFY
  • 20. OPÉRATION DE TERMINALE : MÉTHODE FLATMAP La méthode flatMap transforme chaque Item de la RDD source en 0 ou plusieurs items et retourne une nouvelle RDD. Il s’agit d’un design pattern incontournable de la programmation fonctionnelle. ObjectifObjectif def flatMap[U](f: (T) ⇒ TraversableOnce[U])(implicit arg0: ClassTag[U]): RDD[U] API : scala, Classe : RDD, Package : org.apache.spark Entrée : f est une fonction : (T) ⇒ TraversableOnce[U] Sortie : Une RDD[U] SignatureSignature // créer une RDD comportant les éléments de 1 à 10 val x = sc.parallelize(List((1,2),(3,5),(8,10)) // définir une fonction f val f = (a:Tuple2[Int,Int]) => Seq(a._1, a._2) // appliquer flatMap sur x Val y = x.flatMap(f) // afficher les éléments de y y.collect() //Sortie : res1: Array[Int] = Array(1, 2, 3, 5, 8, 10) ExempleExemple flatMap est similaire à Map La fonction f doit retourner un trait de type TraversableOnce qui consiste à parcourir une collection une ou plusieurs fois. À retenirÀ retenir val z = parallelize(List("La meilleure facon de predire l’avenir est de le creer", "Celui qui veut reussir trouve un moyen", "Celui qui veut rien faire trouve une excuse")) val g = (s:String) => s.split(" ").toList // appliquer la fonction g sur les éléments de z val t = z.flatMap(g) // afficher les éléments de t t.collect() //Sortie : res2: Array[String] = Array(La, meilleure, faþon, de, predire, l'avenir, est, de, le, creer, Celui, qui, veut, reussir, trouve, un, moyen, Celui, qui, veut, rien, faire, trouve, une, excuse) 1 2 20 M.MICHRAFY
  • 21. OPÉRATION DE TRANSFORMATION : MÉTHODE FILTER La méthode filter retourne une RDD ne contenant que les items de la RDD source satisfaisant le prédicat f , passée en argument. Il s’agit aussi d’un design pattern incontournable de la programmation fonctionnelle. ObjectifObjectif def filter(f: (T) ⇒ Boolean): RDD[T] API : scala, Classe : RDD, Package : org.apache.spark Entrée : f est une fonction : (T) => Boolean Sortie : une RDD de type T SignatureSignature // créer un RDD val x = sc.parallelize(List( 7, 10, 12, 17, 19), 2) // x: org.apache.spark.rdd.RDD[Int] = ParallelCollectionRDD[0] at parallelize at <console>:24 // definir une fonction f val f = (a:Int) => (a%2==0) // f: Int => Boolean = <function1> // définir une fonction g Val g = (a:Int) => (a>50) // g: Int => Boolean = <function1> // applique filter avec f et g val zf = x.map(f) // zf: org.apache.spark.rdd.RDD[Boolean] = MapPartitionsRDD[1] at map at <console>:28 val zg = x.map(g) // zg: org.apache.spark.rdd.RDD[Boolean] = MapPartitionsRDD[2] at map at <console>:28 // afficher zf et zg zf.collect() // res0: Array[Boolean] = Array(false, true, true, false, false) Zg.collect() // res2: Array[Boolean] = Array(false, false, false, false, false) ExempleExemple La RDD source et la RDD obtenue ont le même type d’item (T) Le nombre d’éléments de la RDD obtenue est toujours inférieur au nombre d’éléments de la RDD source Il est possible d’obtenir une RDD sans item. À retenirÀ retenir 21 M.MICHRAFY
  • 22. OPÉRATION DE TRANSFORMATION : MÉTHODE SAMPLE La méthode sample retourne un échantillon des données – qui est une sélection aléatoire- de la RDD source. ObjectifObjectif def sample(withRpl: Boolean, fraction: Double, seed: Long = Utils.random.nextLong): RDD[T] API : scala, Classe : RDD, Package : org.apache.spark Entrée : withRpl : avec ou sans répétition fraction : le % des données, dans [0 1] seed : pour initialiser le générateur aléatoire Sortie : une RDD de type T SignatureSignature // créer un RDD de 100 entiers val x = sc.parallelize(1 to 100, 2) // x: org.apache.spark.rdd.RDD[Int] = ParallelCollectionRDD[3] at parallelize at <console>:24 // Faire une selection aléatoire d’un % de 0,1 val smpl1 = x.sample(true, 0.1, 7) // smpl1: org.apache.spark.rdd.RDD[Int] = PartitionwiseSampledRDD[4] at sample at <console>:26 smpl1.collect() // res3: Array[Int] = Array(3, 6, 14, 47, 48, 72, 78, 84, 87, 92, 100) // Faire une selection aléatoire d’un % de 0,3 val smpl2 = x.sample(false, 0.3, 17) // smpl2: org.apache.spark.rdd.RDD[Int] = PartitionwiseSampledRDD[6] at sample at <console>:26 smpl2.collect() // res5: Array[Int] = Array(3, 4, 8, 11, 12, 14, 16, 18, 19, 21, 23, 25, 30, 33, 36, 37, 38, 42, 43, 46, 47, 49, 55, // 58, 61, 64, 69, 70, 73, 74, 76, 80, 86, 89, 96) ExempleExemple Si withRpl = true, on utilise un générateur basé sur la loi de Poisson Si withRpl = false, on utilise un générateur basé sur la loi de Bernoulli. À retenirÀ retenir 22 M.MICHRAFY
  • 23. OPÉRATION DE TRANSFORMATION: MÉTHODE TAKESAMPLE La méthode takeSample retourne un tableau – qui est une sélection aléatoire- de la RDD source. Le nombre d’éléments du tableau est un argument de la méthode takeSample ObjectifObjectif def takeSample(withReplacement: Boolean, num: Int, seed: Long = Utils.random.nextLong): Array[T] API : scala, Classe : RDD, Package : org.apache.spark Entrée : withRpl : avec ou sans répitition num : le nombre d’éléments à retourner seed : pour initialiser le générateur aléatoire Sortie : un tableau de type T (Array[T]) SignatureSignature // créer un RDD de 100 entiers val x = sc.parallelize(1 to 100, 2) // x: org.apache.spark.rdd.RDD[Int] = ParallelCollectionRDD[7] at parallelize at <console>:24 val smpl1take = x.takeSample(true, 10, 7) // smpl1take: Array[Int] = Array(19, 29, 64, 52, 74, 87, 93, 46, 27, 31) val smpl2take = x.takeSample(false, 10, 7) // smpl2take: Array[Int] = Array(41, 80, 72, 24, 90, 100, 56, 87, 50, 78) ExempleExemple Cette méthode retourne exactement un tableau composé de num éléments de la RDD source. Elle est différente de la méthode sample puisque sample prend un argument fraction indiquant le % d’éléments à retourner et retourne une RDD. À retenirÀ retenir 23 M.MICHRAFY
  • 24. OPÉRATION TERMINALE: MÉTHODE TAKEORDERED La méthode takeOrdered ordonne les éléments de données du RDD en utilisant l’ordre implicite (croissant) et renvoie les n premiers éléments sous forme d’un tableau. ObjectifObjectif def takeOrdered(num: Int)(implicit ord: Ordering[T]): Array[T] API : scala, Classe : RDD, Package : org.apache.spark Entrée : num: le nombre d’éléments à retourner Sortie : un tableau de type T (array[T]) SignatureSignature sc.parallelize(Seq(6, 8, 9, 1, 2, 3)).takeOrdered(3) // res1: Array[Int] = Array(1, 2, 3) sc.parallelize(Seq(0, 6, 8, 9, 1, 2, 3)).takeOrdered(3) // res2: Array[Int] = Array(0, 1, 2) sc.parallelize(Seq((1,2),(1,4),(6,7), (9,11), (8,1))).takeOrdered(3) // res3: Array[(Int, Int)] = Array((1,2), (1,4), (6,7)) sc.parallelize(Seq(("aa",2),("bc",4),("ef",7), ("aa",11), ("ef",1))).takeOrdered(3) // res4: Array[(String, Int)] = Array((aa,2), (aa,11), (bc,4)) ExempleExemple Cette méthode est à ne pas utiliser lorsque le tableau retourné est volumineux car les données sont chargées sur la mémoire du driver. Les éléments de la RDD source doivent disposer d’une relation d’ordre À retenirÀ retenir 24 M.MICHRAFY
  • 25. OPÉRATION TERMINALE : MÉTHODE FOLD Agréger les données en deux étapes. Il s’agit d’une opération de type Action. L’étape 1 consiste à appliquer op par partition L’étape 2 consiste appliquer op sur les résultats de la 1 étape op doit être un opérateur associatif ObjectifsObjectifs def fold(zeroValue: T)(op: (T, T) ⇒ T): T API : scala, Classe : rdd, Package : org.apache.spark Entrée : - zeroValue : de type T, c est la valeur initiale de calcul - op est une fonction associative de signature : (T,T) => T Sortie : une valeur de type T SignatureSignature val x = sc.parallelize( 1 to 6, 2) // x: org.apache.spark.rdd.RDD[Int] = ParallelCollectionRDD[0] at parallelize at <console>:24 // calculer la somme de éléments de x via les partitions val op = (a:Int,b:Int) => a+b // op: (Int, Int) => Int = <function2> // zeroValue : 0 x.fold(0)((op) // res10: Int = 21 ExempleExemple Fold et agrgregate sont similaires en terme de processus fold applique le même fonction en 1 et 2 étape Aggregate associe une fonction à chaque étape À retenirÀ retenir 25 M.MICHRAFY
  • 26. OPÉRATION DE TRANSFORMATION : MÉTHODE MAPPARTITIONSWITHINDEX Calculer une nouvelle RDD en appliquant une fonction f sur chaque partition il nécessite au moins un paramètre de type fonction qui prend en entrée les éléments d’une partition et son index ObjectifsObjectifs def mapPartitionsWithIndex[U](f: (Int, Iterator[T]) ⇒ Iterator[U], ind: Boolean = false)(implicit arg0: ClassTag[U]): RDD[U] API : scala, Classe : rdd, Package : org.apache.spark Entrée : - f est une fonction (Int, Iterator[T]) ⇒ Iterator[U] - ind est boolean, dont la valeur par défaut est false, Sortie : RDD[U] SignatureSignature // définir un RDD ( 1 …10) avec 3 partitions val x = sc.parallelize(1 to 10, 3) // x: org.apache.spark.rdd.RDD[Int] = ParallelCollectionRDD[12] at parallelize at <console>:24 // affiche une liste de tuple, chaque tuple est composé de l'index de la partition et la valeur de l'élément. def f[T](i:Int, p:Iterator[T]) : Iterator[(Int,T)] = p.map(w => (i,w)) // f: [T](i: Int, p: Iterator[T])Iterator[(Int, T)] val y = x.mapPartitionsWithIndex(f) // y: org.apache.spark.rdd.RDD[(Int, Int)] = MapPartitionsRDD[13] at mapPartitionsWithIndex at <console>:28 y.collect() // res8: Array[(Int, Int)] = Array((0,1), (0,2), (0,3), (1,4), (1,5), (1,6), (2,7), (2,8), (2,9), (2,10)) ExempleExemple Il est similaire à map map applique une fonction sur les éléments de la RDD alors que mapPartitionsWithIndex applique une fonction f à chaque partition À retenirÀ retenir 26 M.MICHRAFY
  • 27. OPÉRATION TERMINALE : MÉTHODE AGGREGATE Agréger les données en deux étapes. Il s’agit d’une opération de type Action L’étape 1 consiste à appliquer seqOp par partition L’étape 2 consiste à appliquer combOp aux résultats de l’étape 1 ObjectifsObjectifs def aggregate[U](zeroValue: U)(seqOp: (U, T) ⇒ U, combOp: (U, U) ⇒ U)(implicit arg0: ClassTag[U]): U API : scala, Classe : rdd, Package : org.apache.spark Entrée - zeroValue : la valeur initiale de l’accumulateur de type U - seqOp : c’est une fonction associative qui sera appliquée sur chaque partition - comOp : c’est une fonction associative qui s’applique sur les résulats données par seqOp. Sortie : une valeur de retour de type U SignatureSignature val x = sc.parallelize( 1 to 6, 2) // x: org.apache.spark.rdd.RDD[Int] = ParallelCollectionRDD[0] at parallelize at <console>:24 // calculer la somme de éléments de x via les partitions val seqOp = (a:Int,b:Int) => if(a>b) a else b // seqOp: (Int, Int) => Int = <function2> val compOp = (a:Int,b:Int) => a + b // compOp: (Int, Int) => Int = <function2> // affiche une liste de tuple, chaque tuple est composé de l'index de la partition et la valeur de l'élément. def f[T](i:Int, p:Iterator[T]) : Iterator[(Int,T)] = p.map(w => (i,w)) // f: [T](i: Int, p: Iterator[T])Iterator[(Int, T)] // afficher chaque élément et sa partition x.mapPartitionsWithIndex(f).collect() // res4: Array[(Int, Int)] = Array((0,1), (0,2), (0,3), (1,4), (1,5), (1,6), (2,7), (2,8), (2,9), (2,10)) // appliquer la méthode aggregate sur la RDD X x.aggregate(0)( seqOp, compOp) // res10: Int = 19 ExempleExemple 27 M.MICHRAFY
  • 28. OPÉRATION DE TRANSFORMATION : MÉTHODE MAPVALUES La méthode mapValues, s’applique à une RDD de type (K,V) et retourne une RDD de type (K,U). Cette méthode prend en argument une fonction f: (V) ⇒ U, et transforme chaque pair (K,V) en (K, f(U)). C’est une opération de transformation ObjectifObjectif def mapValues[U](f: (V) ⇒ U): RDD[(K, U)] API : scala, Classe : PairRDDFunctions, Package : org.apache.spark Sortie : RDD[(K, U)] SignatureSignature // créer une RDD constitué d’une liste de fruits val x = sc.parallelize(List("Abricot", "Cerise", "Nectarine", "Noisette", "Kiwi")) x: org.apache.spark.rdd.RDD[String] = ParallelCollectionRDD[31] at parallelize at <console>:24 // créer une RDD de type (K,V), avec V = la taille de K val y = x.map(w => (w,w.length)) y// : org.apache.spark.rdd.RDD[(String, Int)] = MapPartitionsRDD[30] at map at <console>:26 // /afficher la RDD y y.collect() // res1: Array[(String, Int)] = Array((Abricot,7), (Cerise,6), (Nectarine,9), (Raisin,6), (Kiwi,4)) // créer une fonction f val f = (n:Int) => (n/2, n%2) // f: Int => (Int, Int) = <function1> ExempleExemple La RDD source et la RDD obtenue ont : • La même taille. • Les mêmes clés • Les mêmes partitions À retenirÀ retenir 28 // appliquer mapValues sur y avec la fonction f val z = y.mapValues(f) //Sortie : z: org.apache.spark.rdd.RDD[(String, (Int, Int))] = MapPartitionsRDD[33] at mapValues at // <console>:30 // afficher le résultat z.collect() res2: Array[(String, (Int, Int))] = Array((Abricot,(3,1)), (Cerise,(3,0)), (Nectarine,(4,1)), (Noisette,(4,0)), (Kiwi,(2,0))) y.Count == z.count res49: Boolean = true 1 2 M.MICHRAFY
  • 29. OPÉRATION TERMINALE : MÉTHODE COLLECT La méthode collect retourne un tableau ( Array) qui représente les éléments de la RDD. Il est utile lors de la mise au point d’un code. ObjectifsObjectifs def collect(): Array[T] API : scala, Classe : rdd, Package : org.apache.spark Sortie : Array[T] SignatureSignature // définir un RDD ( 1 …10) avec 2 partitions val x = sc.parallelize(1 to 10, 2) // x: org.apache.spark.rdd.RDD[Int] = ParallelCollectionRDD[14] at parallelize at <console>:24 // appliquer la méthode collect pour obtenir un tableau val x_arr = x.collect() // x_arr: Array[Int] = Array(1, 2, 3, 4, 5, 6, 7, 8, 9, 10) // Appel sans parenthèse x.Collect // res0: Array[Int] = Array(1, 2, 3, 4, 5, 6, 7, 8, 9, 10) ExempleExemple Cette méthode est couteuse en terme de CPU. Par conséquent, elle est à utiliser seulement si la RDD a un faible volume. À retenirÀ retenir 29 M.MICHRAFY
  • 30. OPÉRATION TERMINALE : MÉTHODE FOREACH La méthode foreach applique une fonction f (T) => Unit, sur chaque élément de la RDD Il est utile lors de la mise au point d’un code. ObjectifsObjectifs def foreach(f: (T) ⇒ Unit): Unit API : scala, Classe : rdd, Package : org.apache.spark Entrée : f une fonction ( (T) => Unit) Sortie : pas de valeur de retour (Unit) SignatureSignature // définir des RDD val x = sc.parallelize(1 to 5, 2) // x: org.apache.spark.rdd.RDD[Int] = ParallelCollectionRDD[15] at parallelize at <console>:24 val y = sc.parallelize(List("Banane", "Kiwi", "Cerise", "Orange", "Fraise"),2) val z = y.zip(x) // z: org.apache.spark.rdd.RDD[(String, Int)] = ZippedPartitionsRDD2[17] at zip at <console>:28 // afficher les éléments de la RDD x x.foreach(w => print(w + ", ")) // 1, 3, 4, 5, 2, // afficher les éléments de la RDD y y.foreach(w => print(w + ", ")) // Cerise, Orange, Banane, Fraise, Kiwi, // afficher les éléments de la RDD z z.foreach(w => print(w + ", ")) // (Banane,1), (Cerise,3), (Orange,4), (Kiwi,2), (Fraise,5), Exemple Attention, foreach n’affiche pas forcement la même chose que la méthode collect À retenirÀ retenir 30 M.MICHRAFY
  • 31. OPÉRATION DE TRANSFORMATION : MÉTHODE COLLECT AVEC DES ARGUMENTS Elle retourne une RDD comportant les éléments correspondant à l'application d’une fonction partielle Cette méthode est couteuse en terme de CPU. Par conséquent, elle est à utiliser seulement si la RDD a un faible volume. ObjectifsObjectifs collect[U](f: PartialFunction[T, U])(implicit arg0: ClassTag[U]): RDD[U] API : scala, Classe : rdd, Package : org.apache.spark Sortie : Array[T] SignatureSignature // créer une rdd avec des éléments de 1 à 10 val sample = sc.parallelize(1 to 10) // sample: org.apache.spark.rdd.RDD[Int] = ParallelCollectionRDD[18] at parallelize at <console>:24 // Déclarer une fonction partielle val isEven: PartialFunction[Int,Int] = { case x if x % 2 == 0 => x } // isEven: PartialFunction[Int,Int] = <function1> // appel de la méthode collect avec l’argument isEven (la fonction partielle) val sample_fp = sample.collect(isEven) // sample_fp: org.apache.spark.rdd.RDD[Int] = MapPartitionsRDD[22] at collect at <console>:30 // afficher les élements de la rdd sample_fp sample_fp.collect() // res11: Array[Int] = Array(2, 4, 6, 8, 10) ExempleExemple Elle est similaire à la méthode collect sans argument. collect() retourne un tableau alors que collect(PartialFunction) retourne une RDD [U] après avoir appliqué la fonction partielle sur les items de la RDD. À retenirÀ retenir 31 M.MICHRAFY
  • 32. OPÉRATION DE TRANSFORMATION : MÉTHODE DISTINCT La méthode distinct retourne une RDD qui comporte les éléments distincts de la RDD source ObjectifsObjectifs def distinct(): RDD[T] API : scala, Classe : rdd, Package : org.apache.spark Sortie : RDD[T] SignatureSignature // créer un rdd avec les éléments : 1,1,2,3,4,5,5 val z = sc.parallelize(List(1,1,2,3,4,5,5)) // z: org.apache.spark.rdd.RDD[Int] = ParallelCollectionRDD[23] at parallelize at <console>:24 // appliquer la méthode distinct sur la rdd z val zsd = z.distinct() // zsd: org.apache.spark.rdd.RDD[Int] = MapPartitionsRDD[26] at distinct at <console>:26 // regrouper le resultat dans un tableau zsd.collect() // res12: Array[Int] = Array(4, 1, 5, 2, 3) val l = List(List(1,2),List(3,4), List(4,3), List(1,2), List(1,2,3,4)) // l: List[List[Int]] = List(List(1, 2), List(3, 4), List(4, 3), List(1, 2), List(1, 2, 3, 4)) val zobj = sc.parallelize(l) // zobj: org.apache.spark.rdd.RDD[List[Int]] = ParallelCollectionRDD[27] at parallelize at <console>:26 // observer le resultat val zobjsd = zobj.distinct() // zobjsd: org.apache.spark.rdd.RDD[List[Int]] = MapPartitionsRDD[30] at distinct at <console>:28 zobjsd.collect() // res14: Array[List[Int]] = Array(List(3, 4), List(1, 2, 3, 4), List(4, 3), List(1, 2)) ExempleExemple Il est possible de mettre en place la méthode distinct en utilisant : • map • reduceByKey À retenirÀ retenir 32 M.MICHRAFY
  • 33. OPÉRATION DE TRANSFORMATION : MÉTHODE UNION La méthode union retourne une RDD qui est l’union des items de la RDD source et de la RDD passée en argument. il est possible d’avoir des éléments identiques dans la RDD résultat. Pour éviter cela, utiliser la méthode distinct ObjectifsObjectifs def union(other: RDD[T]): RDD[T] API : scala, Classe : rdd, Package : org.apache.spark Entrée : other est de type RDD[T]. Sortie : RDD[T] SignatureSignature // créer les rdd avec les éléments : 1 to 10, et 5 to 15 val x = sc.parallelize(1 to 10) // x: org.apache.spark.rdd.RDD[Int] = ParallelCollectionRDD[31] at parallelize at <console>:24 val y = sc.parallelize(5 to 15) // y: org.apache.spark.rdd.RDD[Int] = ParallelCollectionRDD[32] at parallelize at <console>:24 // appliquer la méthode union val uad = x.union(y) // uad: org.apache.spark.rdd.RDD[Int] = UnionRDD[33] at union at <console>:28 // appliquer la méthode union et supprimer les éléments identiques val usd = x.union(y).distinct() // usd: org.apache.spark.rdd.RDD[Int] = MapPartitionsRDD[37] at distinct at <console>:28 // afficher les résultats uad.collect() // res15: Array[Int] = Array(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15) usd.collect() // res16: Array[Int] = Array(8, 1, 9, 10, 2, 11, 3, 4, 12, 13, 5, 14, 6, 15, 7) ExempleExemple Les éléments de la RDD source et la rdd other doivent être de même type (ici T) Plus précisément, les éléments de la RDD other doivent être de même type que ceux de la rdd source. À retenirÀ retenir 33 M.MICHRAFY
  • 34. OPÉRATION DE TRANSFORMATION : MÉTHODE INTERSECTION La méthode intersection retourne une RDD qui est l’intersection des items du RDD source et de la RDD passée en argument. Attention, le résultat de retour ne comporte pas de doublant même si la RDD source ou argument en comporte. ObjectifsObjectifs def intersection(other: RDD[T]): RDD[T] API : scala, Classe : rdd, Package : org.apache.spark Entrée : other est de type RDD[T]. Sortie : RDD[T] SignatureSignature // créer deux rdds val x = sc.parallelize(List(1 , 1, 2, 3, 4, 7)) // x: org.apache.spark.rdd.RDD[Int] = ParallelCollectionRDD[38] at parallelize at <console>:24 val y = = sc.parallelize(List(1, 1, 4, 4, 5, 6)) // y: org.apache.spark.rdd.RDD[Int] = ParallelCollectionRDD[39] at parallelize at <console>:24 // appliquer la méthode intersection val z = x. intersection(y) // z: org.apache.spark.rdd.RDD[Int] = MapPartitionsRDD[45] at intersection at <console>:28 // afficher les résultats z.collect() // res17: Array[Int] = Array(4, 1) ExempleExemple Les éléments de la RDD other doivent être de même type que ceux de la rdd source. intersection peut être codée avec : • map, • cogroup • filter À retenirÀ retenir 34 M.MICHRAFY
  • 35. OPÉRATION DE TRANSFORMATION : MÉTHODE SUBTRACT La méthode subtract est l’implémentation de l’opération soustraction au sens ensemble. Elle retourne les éléments de la RDD source mais qui ne sont pas dans la RDD passée en argument. ObjectifsObjectifs def subtract(other: RDD[T]): RDD[T] API : scala, Classe : rdd, Package : org.apache.spark Entrée : other est de type RDD[T] Sortie : RDD[T] SignatureSignature // créer les 2 rdds val x = sc.parallelize(1 to 5, 2) val y = sc.parallelize(3 to 7, 2) x.collect() // res18: Array[Int] = Array(1, 2, 3, 4, 5) y.collect() // res19: Array[Int] = Array(3, 4, 5, 6, 7) // appliquer la méthode subtract et generer la RDD s val s = x.subtract(y) // afficher les éléments s.collect() // res20: Array[Int] = Array(2, 1) ExempleExemple La RDD other doit être de même type que la RDD source. Dans le cas contraire, on obtient une erreur. Il existe des variante de subtract portant sur le nombre des partitions. À retenirÀ retenir // créer une RDD val z = sc.parallelize(List("A","B","D","E"),2) // appliquer la méthode subtract sur x et z // cette instruction génère une erreur val t = x.subtract(z) error: type mismatch; found : org.apache.spark.rdd.RDD[String] required: org.apache.spark.rdd.RDD[Int] val t = x.subtract(z) 1 2 35 M.MICHRAFY
  • 36. OPÉRATION DE TRANSFORMATION : MÉTHODE ZIP La méthode zip consiste à construire une RDD de type (K,V) à partir de la RDD[K] source et la RDD[V] passée en argument. L’élément i de la RDD résultante est (ki,vi) avec ki, vi les éléments d’indice i resp. des RDD source et argument. ObjectifsObjectifs def zip[U](other: RDD[U])(implicit arg0: ClassTag[U]): RDD[(T, U)] API : scala, Classe : rdd, Package : org.apache.spark Entrée : other est de type RDD[U]. Sortie : un RDD de type (T,U) SignatureSignature // créer les deux rdds val key = sc.parallelize(1 to 5, 2) val value = sc.parallelize(11 to 15, 2 ) // appliquer la méthode zip val x = key.zip(value) // afficher les éléments x.collect() // res21: Array[(Int, Int)] = Array((1,11), (2,12), (3,13), (4,14), (5,15)) Exemple 1Exemple 1 Pour réaliser une opération zip, les deux RDD doivent avoir : • Le même nombre de partitions • Le même nombre d'éléments dans chaque Partition À retenirÀ retenir // créer deux rdds val value_nes = sc.parallelize(11 to 16, 2 ) val value_nps = sc.parallelize(11 to 15, 3 ) // appliquer la méthode zip val x_nes = key.zip(value_nes) val x_nps = key.zip(value_nep) // Des exceptions se lèvent lors de l’appel de collect X_nex.collect() // error : Can only zip RDDs with same number of elements in each partition x_nep.collect() // error : Can't zip RDDs with unequal numbers of partitions Exemple 2Exemple 2 36 M.MICHRAFY
  • 37. OPÉRATION DE TRANSFORMATION : MÉTHODE GROUPBY La méthode groupBy regroupe les éléments de la RDD[T] source par clé et retourne une RDD [(k, Iterable[T])] Elle prend en entrée une fonction f : (T) => K, qui s’applique à chaque élément de la RDD source pour générer les clés de la RDD retournée. ObjectifObjectif def groupBy[K](f: (T) ⇒ K)(implicit kt: ClassTag[K]): RDD[(K, Iterable[T])] API : scala, Classe : RDD Package : org.apache.spark Sortie : RDD[(K, Iterable[T])] SignatureSignature // créer la rdd de type (Int) avec 10 partitions val x = sc.parallelize(1 to 20, 10) // faire une selection aléatoire dans les éléments de x val y = x.sample(false, 0.1, 19) // definir la function f val f = (w:Int) => w%3 // f: Int => Int = <function1> // définir une fonction g val g = (w:Int) => 2*w + 7 // g: Int => Int = <function1> ExempleExemple Cette méthode est très couteuse. Il existe deux variantes de cette méthode, prenant en plus soit le nombre de partitions, soit un partitionner Attention la RDD est de type (K, Iterable[T])], sachant que f : (T) => K Elle est similaire avec la méthode groupByKey À retenirÀ retenir // appliquer la groupBy , avec f, sur les éléments de y val z = y.groupBy(f) // appliquer groupBy, avec g, sur les éléments de y val s = y.groupBy(g) // afficher z et s z.collect() // res25: Array[(Int, Iterable[Int])] = Array((0,CompactBuffer(6, 15))) s.collect() // res26: Array[(Int, Iterable[Int])] = Array((37,CompactBuffer(15)), (19,CompactBuffer(6))) 1 2 37 M.MICHRAFY
  • 38. OPÉRATION DE TRANSFORMATION : MÉTHODE GROUPBYKEY Pour une RDD de type (K, V), groupByKey retourne une RDD de type (K,Iterable<V>) Si le regroupement vise une agrégation, pour des raisons de performance, il est conseillé d’utiliser reduceByKey ou aggregateByKey. ObjectifObjectif def groupByKey(): RDD[(K, Iterable[V])] API : scala, Classe : PairRDDFunctions, Package : org.apache.spark Sortie : RDD[(K, Iterable[V])] SignatureSignature // créer la rdd de type (k,v) avec deux partitions val x = sc.parallelize(List((1,1),(11,2),(11,6),(2,8),(3,5),(3,7)),2) // x: org.apache.spark.rdd.RDD[(Int, Int)] = ParallelCollectionRDD[67] at parallelize at <console>:24 // appliquer la méthode groupeByKey pour regrouper par clé val z = x.groupByKey() // z: org.apache.spark.rdd.RDD[(Int, Iterable[Int])] = ShuffledRDD[68] at groupByKey at <console>:26 // afficher les données de la RDD z z.collect() // res27: Array[(Int, Iterable[Int])] = Array((2,CompactBuffer(8)), (11,CompactBuffer(2, 6)), (1,CompactBuffer(1)), (3,CompactBuffer(5, 7))) ExempleExemple groupByKey est une méthode de la classe PairRDDFunctions. Elle s’applique à des RDD de type (k,v). groupByKey utilise un partitionner par défaut Il existe différente variante de cette méthode : - def groupByKey(numPartitions: Int): RDD[(K, Iterable[V])] - def groupByKey(partitioner: Partitioner): RDD[(K, Iterable[V])] À retenirÀ retenir 38 M.MICHRAFY
  • 39. OPÉRATION DE TRANSFORMATION : MÉTHODE REDUCEBYKEY Pour une RDD de type (k,v), reduceByKey retourne une RDD de type (k,v) où les valeurs de chaque clé sont agrégées en utilisant la fonction f de type (v,v) => v. ObjectifObjectif def reduceByKey(func: (V, V) ⇒ V): RDD[(K, V)] API : scala, Classe : PairRDDFunctions, Package : org.apache.spark Entrée : une fonction associative, commutative de type (v,v) => v Sortie RDD[(K, V)] SignatureSignature // créer la rdd de type (k,v) avec deux partitions val t = Seq((1,1),(1,8), (2,7), (2,9), (3,13), (3, 10)) val x = sc.parallelize(t, 2) // // x: org.apache.spark.rdd.RDD[(Int, Int)] = ParallelCollectionRDD[4] at parallelize at <console>:24 // créer la fonction func val func = (x:Int, y:Int) => x + y // func: (Int, Int) => Int = <function2> // appliquer la méthode reduceByKey pour regrouper par clé et appliquer func val y = x.reduceByKey(func) // y: org.apache.spark.rdd.RDD[(Int, Int)] = ShuffledRDD[5] at reduceByKey at <console>:32 x.collect() // // res2: Array[(Int, Int)] = Array((1,1), (1,8), (2,7), (2,9), (3,13), (3,10)) // afficher les résultats y.collect() // res3: Array[(Int, Int)] = Array((2,16), (1,9), (3,23)) ExempleExemple reduceByKey estune méthode de la classe PairRDDFunctions. il existe deux variantes de cette méthode nécessitant en plus soit le nombre de partitions soit un partitionner. À retenirÀ retenir 39 M.MICHRAFY
  • 40. OPÉRATION DE TRANSFORMATION : MÉTHODE AGGREGATEBYKEY Pour une RDD[(k,v)], aggregateByKey retourne une RDD[(k,u)] où les valeurs de chaque clé sont agrégées en appliquant les fonctions seqOp et combOp et la valeur neutre zeroValue. Elle est similaire à aggregate sauf que l'agrégation est appliquée aux valeurs ayant la même clé ObjectifObjectif def aggregateByKey[U](zero: U)(seqOp: (U, V) ⇒ U, combOp: (U, U) ⇒ U)(implicit arg0: ClassTag[U]): RDD[(K, U)] API : scala, Classe : PairRDDFunctions, Package : org.apache.spark Entrée : zero valeur neutre de type U seqOp : (U,V) => U et CombOp : (U,U) => U Sortie : RDD[(K, V)] SignatureSignature // créer la rdd de type (k,v) avec deux partitions val x = sc.parallelize(List(("Bannane", 4),("Fraise", 1),("Bannane", 3),("Kiwi", 2),("Fraise", 2),("Orange", 5),("Orange",6),("Raisin",4)),2) // Pour chaque élément de la RDD x, afficher sa partition et sa valeur x.mapPartitionsWithIndex((i,p) => p.map(w => (i,w))).collect() // res28: Array[(Int, (String, Int))] = Array((0,(Bannane,4)), (0,(Fraise,1)), (0,(Bannane,3)), (0,(Kiwi,2)), (1,(Fraise,2)), (1,(Orange,5)), (1,(Orange,6)), (1,(Raisin,4))) // créer deux fonctions seqOp et combOp val seqOp = (a:Int, b:Int) => Math.max(a,b) // seqOp: (Int, Int) => Int = <function2> val combOp = (a:Int, b:Int) => a + b // combOp: (Int, Int) => Int = <function2> // appliquer la méthode aggregateByKey val y = x.aggregateByKey(0)(seqOp, combOp) // y: org.apache.spark.rdd.RDD[(String, Int)] = ShuffledRDD[76] at aggregateByKey at <console>:30 // afficher les résultats y.collect() // res29: Array[(String, Int)] = Array((Raisin,4), (Kiwi,2), (Fraise,3), (Orange,6), (Bannane,4)) ExempleExemple aggregateByKey est une méthode de la classe PairRDDFunctions. il existe deux variantes de cette méthode nécessitant en plus soit le nombre de partitions soit un partitionner. À retenirÀ retenir 40 M.MICHRAFY
  • 41. OPÉRATION DE TRANSFORMATION : MÉTHODE SORTBYKEY Pour une RDD[(k,v)], sortByKey retourne une RDD[(k,v)] triée selon un ordre prédéfini La clé doit implémenter le trait Ordered ObjectifObjectif def sortByKey(ascending: Boolean = true, numPartitions: Int = self.partitions.length): RDD[(K, V)] API : scala, Classe : OrderedRDDFunctions, Package : org.apache.spark Entrée : ascending boolean indiquant le type de trie numPartitions, optionnel, indique le nombre de partitions Sortie : RDD[(K, V)] SignatureSignature // créer une rdd de type (k,v) val x = sc.parallelize(List(("B", 4),("K", 2),("F", 2),("O", 5),("R",4)),3) // appliquer la méthode sortByKey val yas = x.sortByKey(true) val yde = x.sortByKey(false) // afficher les résultats yas.collect() // res30: Array[(String, Int)] = Array((B,4), (F,2), (K,2), (O,5), (R,4)) yde.collect() // res32: Array[(String, Int)] = Array((R,4), (O,5), (K,2), (F,2), (B,4)) Exemple 1Exemple 1 sortByKey est une méthode de la classe OrderedRDDFunctions. Par conséquent, la RDD source doit avoir des élements de type (K,V) À retenirÀ retenir case class A(tag:String, load:Int) extends Ordered[A] { def compare( a:A ) = tag.compareTo(a.tag) } // créer une rdd de type (k,v) val xls = List( A("w",50), A("v",2), A("l",7), A("s",6)) val xlsrdd = sc.parallelize(xls,2) val v = sc.parallelize(1 to 4,2) val xx = xlsrdd.zip(v) // appliquer la méthode sortByKey val yy = xx.sortByKey(true) // afficher les résultats yy.collect() // Array[(A, Int)] = Array((A(l,7),3), (A(s,6),4), (A(v,2),2), (A(w,50),1)) Exemple 2Exemple 2 41 M.MICHRAFY
  • 42. OPÉRATION DE TRANSFORMATION : MÉTHODE JOIN La méthode join nécessite des RDD de type (K,V) Elle permet de faire une jointure sur la clé entre la RDD source et la RDD passée en argument. La valeur de retour est une RDD de type (K, (V, W)) ObjectifObjectif def join[W](other: RDD[(K, W)]): RDD[(K, (V, W))] API : scala, Classe : PairRDDFunctions, Package : org.apache.spark Entrée : other est une RDD de type (K,W) Sortie : RDD[(K, (V, W))] SignatureSignature // créer des rdd de type (k,v) val l1 = List(("A",1),("B",2),("C",3),("D",5),("E",1)) Val l2 = List(("A",2),("E",2),("C",5),("D",5),("G",1)) val x = sc.parallelize(l1,2) //x: org.apache.spark.rdd.RDD[(String, Int)] = ParallelCollectionRDD[7] at parallelize at <console>:26 val y = sc.parallelize(l2, 2) // y: org.apache.spark.rdd.RDD[(String, Int)] = ParallelCollectionRDD[8] at parallelize at <console>:26 // appliquer la méthode join // z: org.apache.spark.rdd.RDD[(String, (Int, Int))] = MapPartitionsRDD[11] at join at <console>:32 val z = x.join(y) // afficher les résultats z.collect() // res1: Array[(String, (Int, Int))] = Array((D,(5,5)), (A,(1,2)), (C,(3,5)), (E,(1,2))) il existe deux variantes de cette méthode nécessitant en plus soit le nombre de partitions soit un partitionner. il existe aussi une jointure à droite ou à gauche ( voir leftOuterJoin, rightOuterJoin) À retenirÀ retenir ExempleExemple 42 M.MICHRAFY
  • 43. OPÉRATION DE TRANSFORMATION : MÉTHODE CARTESIAN La méthode cartesian retourne une RDD[(K,V)] qui est le produit cartésien de la RDD source et la RDD argument. La RDD retournée est de taille nxm avec n, m les nombres d’éléments de la RDD source et la RDD passée en argument. ObjectifObjectif def cartesian[U](other: RDD[U])(implicit arg0: ClassTag[U]): RDD[(T, U)] API : scala, Classe : RDD, Package : org.apache.spark Entrée : other est une RDD de type U Sortie : une RDD de type (T,U) SignatureSignature // créer deux RDD val x = sc.parallelize( 1 to 5, 2) // x: org.apache.spark.rdd.RDD[Int] = ParallelCollectionRDD[12] at parallelize at <console>:24 val y = sc.parallelize(List(("A",2),("E",2),("C",5)), 2) // y: org.apache.spark.rdd.RDD[(String, Int)] = ParallelCollectionRDD[13] at parallelize at <console>:24 // calculer le produit cartésien de x et y val z = x. cartesian(y) // z: org.apache.spark.rdd.RDD[(Int, (String, Int))] = CartesianRDD[14] at cartesian at <console>:28 // évaluer la taille de z // res3: Boolean = true z.count() == x.count () * y.count() // afficher les éléments de z // res4: Array[(Int, (String, Int))] = Array((1,(A,2)), (2,(A,2)), (1,(E,2)), (1,(C,5)), (2,(E,2)), (2,(C,5)), (3,(A,2)), z.collect() // (4,(A,2)), (5,(A,2)), (3,(E,2)), (3,(C,5)), (4,(E,2)), (4,(C,5)), (5,(E,2)), (5,(C,5))) ExempleExemple La RDD retournée est une instance de la classe PairRDDFunctions, Pour un élément (k,v) de la RDD retournée, k est un élément de la RDD source et v est un élément de la RDD passée en argument À retenirÀ retenir 43 M.MICHRAFY
  • 44. OPÉRATION DE TRANSFORMATION : MÉTHODE COGROUP Pour une RDD source (K,V) et une RDD de type (K,W), la méthode cogroup retourne une RDD de type (K, (Iterable<V>, Iterable<W>)). ObjectifObjectif def cogroup[W](other: RDD[(K, W)]): RDD[(K, (Iterable[V], Iterable[W]))] API : scala, Classe : PairRDDFunctions, Package : org.apache.spark Entrée : other est une RDD de type (K,W) Sortie : une RDD de type [(K, (Iterable[V], Iterable[W])) SignatureSignature // créer deux RDD de type clé-valeur val x = sc.parallelize(List(("A",1), ("A",2),("C",5), ("D",10),("D",1)), 2) val y = sc.parallelize(List(("A",3), ("B",3), ("B",6), ,("C",7)), 2) // regrouper par clé val z = x. cogroup(y) // RDD[(String, (Iterable[Int], Iterable[Int]))] = MapPartitionsRDD[18] at cogroup at <console>:28 // comparer le nombre des clés distinct avec celui du nombre d’éléments de z x.map(w => w._1).union(y.map(w => w._1)).distinct().count() == z.count() // res5: Boolean = true // calculer le nombre des éléments de z z.count() // res6: Long = 4 // afficher les éléments de z z.collect() // res7: Array[(String, (Iterable[Int], Iterable[Int]))] = Array((B,(CompactBuffer(),CompactBuffer(3, 6))), (D,(CompactBuffer(10,1),CompactBuffer())), // (A,(CompactBuffer(1, 2),CompactBuffer(3))), (C,(CompactBuffer(5),CompactBuffer(7)))) Cette méthode a plusieurs variantes : 2 à 3 arguments de type RDD[(K,W)] Le nombre de partitions Le nombre d’éléments de la RDD obtenue est égal au nombre de clés distinctes dans les deux RDD. SI une clé est absente d’une RDD alors sa valeur est remplacé par vide. À retenirÀ retenir ExempleExemple 44 M.MICHRAFY
  • 45. OPÉRATION DE TRANSFORMATION : MÉTHODE COALESCE La méthode coalesce regroupe les données de la RDD source dans un nombre de données de partitions. ObjectifObjectif def coalesce(numPartitions: Int, shuffle: Boolean = false, partitionCoalescer: Option[PartitionCoalescer] = Option.empty)(implicit ord: Ordering[T] = null): RDD[T] API : scala, Classe : RDD, Package : org.apache.spark Entrée : numPartitions le nombre de partitions visé shuffle pour l’étape de shuffle, par défaut false partitionCoalescer optionnel, indique la manière de fusionner les partitions Sortie : une RDD de type T SignatureSignature // créer une RDD avec 50 partitions val x = sc.parallelize( 1 to 1000, 50) // x: org.apache.spark.rdd.RDD[Int] = ParallelCollectionRDD[25] at parallelize at <console>:24 // appliquer coalesce val y = x. coalesce(10, true) // y: org.apache.spark.rdd.RDD[Int] = MapPartitionsRDD[29] at coalesce at <console>:26 val z = x.coalesce(3, false) // z: org.apache.spark.rdd.RDD[Int] = CoalescedRDD[30] at coalesce at <console>:26 // afficher les partitions y. getNumPartitions // res8: Int = 10 z. getNumPartitions // res9: Int = 3 ExempleExemple La méthode coalesce est similaire à la méthode repartition Elle permet de contrôler le nombre de partitions d’ une RDD À retenirÀ retenir 45 M.MICHRAFY
  • 46. OPÉRATION DE TRANSFORMATION : MÉTHODE REPARTITION La méthode repartition regroupe les données de la RDD source dans un nombre donné de partitions. ObjectifObjectif def repartition(numPartitions: Int)(implicit ord: Ordering[T] = null): RDD[T] API : scala, Classe : RDD, Package : org.apache.spark Entrée : numPartitions le nombre de partitions visé Sortie : une RDD de type T SignatureSignature // créer une RDD avec 50 partitions val x = sc.parallelize( 1 to 1000, 50) // x: org.apache.spark.rdd.RDD[Int] = ParallelCollectionRDD[31] at parallelize at <console>:24 // appliquer repartition val y = x. repartition(10) // y: org.apache.spark.rdd.RDD[Int] = MapPartitionsRDD[35] at repartition at <console>:26 // afficher le nombre de partitions y. getNumPartitions // res10: Int = 10 ExempleExemple La méthode repartition est similaire à la méthode coalesce. Cette méthode fait appel à la méthode coalesce avec les deux arguments : numPartitions et shuffle=true À retenirÀ retenir 46 M.MICHRAFY
  • 47. OPÉRATION DE TRANSFORMATION : MÉTHODE SAVEASTEXTFILE La méthode saveAsTextFile enregistre le contenu de la RDD dans le dossier passé en argument ObjectifObjectif def saveAsTextFile(path: String): Unit API : scala, Classe : RDD, Package : org.apache.spark Entrée : path le nom fichier Sortie : pas de valeur de retour (Unit). SignatureSignature // créer une RDD avec 50 partitions val x = sc.parallelize( 1 to 20, 3) val y = sc.parallelize(List((1,2),(3,5),(6,7),(8,10),(11,15),(18,20)), 2) // enregistrer les données de la RDD x dans rdd_x x.saveAsTextFile("rdd_x") // un dossier rdd_x est crée avec des fichiers contenant les données de chaque partition // enregistrer les données de la RDD y dans rdd_x y.saveAsTextFile("rdd_x") // Une exception se déclenche puisque le dossier rdd_x existe ExempleExemple saveAsTextFile crée un dossier path et enregistre les données de chaque partition dans un fichier part-0000x où x est un entier. Si le dossier path existe alors une exception se déclenche. À retenirÀ retenir 47 M.MICHRAFY
  • 48. DR MUSTAPHA MICHRAFY CONTACT : DATASCIENCE.KM@GMAIL.COM