Spark RDD : Transformations & Actions
-
Upload
michrafy-mustafa -
Category
Data & Analytics
-
view
355 -
download
10
Transcript of Spark RDD : Transformations & Actions
APACHE SPARKRDD : TRANSFORMATIONS, ACTIONS PAS À PAS
DR MUSTAPHA MICHRAFY
CONTACT : [email protected]
CONTEXTE
Cette étude a été menée dans le cadre desrencontres de travail organisées auLaboratoire CERMSEM, Centre d'Économie dela Sorbonne (CES).
2
M.MICHRAFY
PLAN
1. Contexte2. Objectif et prérequis3. Spark Définition et motivations4. Positionnement de Spark dans l’eco-systeme Big Data5. Composants de spark6. Spark driver et workers7. Apache Spark : vue logique et APIs8. Vue globale sur les API Spark : dépendance et interaction9. RDD, caractéristiques, création et Operations10.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 Sparkpas à pas. Il s’agit d’explorer les opérations(transformations et actions) relatives à lastructure 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
LocalThreads
WorkerExecutor
WorkerExecutor
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 MLSparkStreaming
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 traitementdes données structurées avec une syntaxesimilaire à SQL. Il permet d’extraire, transformeret charger des données sous différents formats(CSV, JSON, Parquet, base de données) et lesexposer pour des requêtes ad-hoc.
� Spark ML est une librairiedédiée aux méthodesd’apprentissage distribués :
� Classification� Clustering� Régression� Filtrage collaboratif� Réduction de dimension
� Spark Core est le moteur de calcul etd’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 typetransformation et Action.
� Spark Streaming est dédié au traitementtemps-réel des données en flux. Il offre unmode de traitement en micro-batch etsupportant différentes sources de données(Kafka, Flume, Kinesis ou TCP sockets …).
� Spark GraphX est dédié au traitement et à laparallélisation de graphes. Ce module offre desopérateurs et des algorithmes pour letraitement des graphes. GraphX étend les RDDde Spark via la Resilient Distributed DatasetGraph (RDDG)
� SparkR est un package R offrant une interfacelégère pour utiliser Spark à partir de R. DansSpark 2.0.2, SparkR fournit une implémentationde la Dataframe distribuée supportant desopérations telles que la sélection, le filtrage,l'agrégation. SparkR offre aussi des algorithmesd’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 partitions2. Une RDD est associée à une liste de
dépendances avec les RDD parents3. Une RDD dispose d’une fonction pour calculer
une partition4. Optionnellement, un objet « partionner » pour
les RDD de type clé/valeur5. Optionnellement, une liste indiquant
l’emplacement pour chaque partition
CaractéristiquesCaractéristiques
� RDD supporte deux type d’opérations1. Transformation2. Action
� Une transformation consiste àappliquer une fonction sur 1 à n RDDet à retourner une nouvelle RDD
� Une action consiste à appliquer unefonction et à retourner une valeur
OpérationsOpérations
1. Les transformations sontparesseuses, évitant le calcul inutile.Ceci favorise l’optimisation dutraitement.
2. Une RDD transformée est calculéelorsqu’une action est appliquée surcette dernière.
Evaluation LazyEvaluation Lazy
Resilient Distributed Dataset (RDD)
Resilient : supporte la tolérance aux pannes grâce à unemodélisation du processus d’exécution par un DAG (directedacyclic 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 RDD1. A partir d’une source de données2. En parallélisant une collection via
SparkContext3. En appliquant une opération de
type transformation sur la RDD
CréationCréation
� Certaines fonctions sont disponiblesseulement sur certains types de RDD :
1. mean, variance, stdev pour les RDDnumériques
2. Join pour les RDD clé/valeur3. L’enregistrement de fichier utilisant
des RDD basées sur des fichiers deformat séquentiel.
� Pour plus de détails, voir les RDD de typeo PairRDDFunctions,o DoubleRDDFunctions,o SequenceFileRDDFunctions
Fonction/type RDDFonction/type RDD
In-MemoryImmutable
Lazy
evaluated
Lazy
evaluated
CacheableParallele
TypedPartitioned
Resilient
RDD
� Spark supporte de charger oud’enregistrer des fichiers dansdivers formats : non structuré, semi-structuré, structuré.
� Les formats sont :o Texto Jsono CSVo SequenceFileo Protocole bufferso 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 objectif2. La signature de l’opération3. 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 RDDen appliquant une fonction passéeen argument à chaque item de laRDD source
� Il s’agit d’un design patternincontournable de la programmationfonctionnelle.
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) => USortie : 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 enappliquant une fonctioncommutative et associative passéeen argument.
� C’est une opération terminale� Il s’agit d’un design pattern
incontournable de la programmationfonctionnelle.
ObjectifObjectif
def reduce(f: (T, T) ⇒ T): T
API : scala, Classe : RDD, Package : org.apache.spark
Entrée : f est une fonction : (T,T) => TSortie : 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 lenombre d’éléments d’une RDDsource.
� 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 lenombre de valeur par clé et retouneune map
� Cette méthode nécessite une RDDde 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 untableau d’éléments, constitué des npremiers éléments de la RDD source.
� Le nombre d’éléments à retourner estl’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 à retournerSortie : 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 transformechaque Item de la RDD source en0 ou plusieurs items et retourneune nouvelle RDD.
� Il s’agit d’un design patternincontournable de laprogrammation fonctionnelle.
ObjectifObjectif
def flatMap[U](f: (T) ⇒ TraversableOnce[U])(implicitarg0: 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 RDDne contenant que les items de la RDDsource satisfaisant le prédicat f , passéeen argument.
� Il s’agit aussi d’un design patternincontournable de la programmationfonctionnelle.
ObjectifObjectif
def filter(f: (T) ⇒ Boolean): RDD[T]
API : scala, Classe : RDD, Package : org.apache.spark
Entrée : f est une fonction : (T) => BooleanSortie : 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 unesélection aléatoire- de la RDDsource.
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étitionfraction : 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 untableau – qui est une sélectionaléatoire- de la RDD source.
� Le nombre d’éléments du tableau estun argument de la méthodetakeSample
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épititionnum : le nombre d’éléments à retournerseed : 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 ordonneles éléments de données du RDD enutilisant l’ordre implicite (croissant) etrenvoie les n premiers éléments sousforme 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
ObjectifsObjectifsdef 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
ObjectifsObjectifsdef 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 mapPartitionsWithIndexapplique 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 combOpaux résultats de l’étape 1
ObjectifsObjectifsdef 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 partitionx.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 uneRDD de type (K,U).
� Cette méthode prend en argumentune fonction f: (V) ⇒ U, et transformechaque 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 obtenueont :
• 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.
ObjectifsObjectifsdef 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èsex.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.
ObjectifsObjectifsdef 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>:24val 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 xx.foreach(w => print(w + ", ")) // 1, 3, 4, 5, 2,
// afficher les éléments de la RDD yy.foreach(w => print(w + ", ")) // Cerise, Orange, Banane, Fraise, Kiwi,
// afficher les éléments de la RDD zz.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
ObjectifsObjectifsdef 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 rddsource.
À 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.
ObjectifsObjectifsdef 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 otherdoivent ê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.
ObjectifsObjectifsdef 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 subtractportant 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.
ObjectifsObjectifsdef 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.
ObjectifObjectifdef 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.
ObjectifObjectifdef 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 detype (k,v) où les valeurs de chaqueclé sont agrégées en utilisant lafonction f de type (v,v) => v.
ObjectifObjectifdef 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)], aggregateByKeyretourne une RDD[(k,u)] où les valeursde chaque clé sont agrégées enappliquant les fonctions seqOp etcombOp et la valeur neutrezeroValue.
� Elle est similaire à aggregate saufque l'agrégation est appliquée auxvaleurs 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)], sortByKeyretourne une RDD[(k,v)] triée selon unordre prédéfini
� La clé doit implémenter le traitOrdered
ObjectifObjectif
def sortByKey(ascending: Boolean = true, numPartitions: Int = self.partitions.length): RDD[(K, V)]
API : scala, Classe : OrderedRDDFunctions, Package : org.apache.sparkEntrée : ascending boolean indiquant le type de trie
numPartitions, optionnel, indique le nombrede 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 RDDde type (K,V)
� Elle permet de faire une jointure sur laclé entre la RDD source et la RDDpassée en argument.
� La valeur de retour est une RDD detype (K, (V, W))
ObjectifObjectif
def join[W](other: RDD[(K, W)]): RDD[(K, (V, W))]
API : scala, Classe : PairRDDFunctions, Package : org.apache.sparkEntré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 uneRDD[(K,V)] qui est le produit cartésiende la RDD source et la RDDargument.
� La RDD retournée est de taille nxmavec n, m les nombres d’éléments dela RDD source et la RDD passée enargument.
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 USortie : 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 uneRDD de type (K,W), la méthodecogroup retourne une RDD detype (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 coalesceregroupe les données de laRDD source dans un nombrede données de partitions.
ObjectifObjectifdef 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.sparkEntrée : numPartitions le nombre de partitions visé
shuffle pour l’étape de shuffle, par défaut falsepartitionCoalescer 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 repartitionregroupe les données de laRDD source dans un nombredonné de partitions.
ObjectifObjectifdef 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 repartitionest 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 saveAsTextFileenregistre le contenu de laRDD dans le dossier passé enargument
ObjectifObjectifdef 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 : [email protected]