Spark RDD : Transformations & Actions

6 670 vues

Publié le

Ce étude vise à présenter la platforme Spark et les opérations (Transformation et Action) d'une RDD. Les points abordés sont Spark motivation, Positionnement de Spark dans l'écosystème BigData, Composants de Spark, Drivers et Workers, RDD & caractéristiques, vue logique de spark, vue globale sur les APIs Spark (dépendance et interaction), les différentes opérations de spark. Chaque opération est sur une fiche (objectif, signature, "à retenir" et exemple de code).

Publié dans : Données & analyses
1 commentaire
8 j’aime
Statistiques
Remarques
Aucun téléchargement
Vues
Nombre de vues
6 670
Sur SlideShare
0
Issues des intégrations
0
Intégrations
0
Actions
Partages
0
Téléchargements
94
Commentaires
1
J’aime
8
Intégrations 0
Aucune incorporation

Aucune remarque pour cette diapositive

Spark RDD : Transformations & Actions

  1. 1. APACHE SPARK RDD : TRANSFORMATIONS, ACTIONS PAS À PAS DR MUSTAPHA MICHRAFY CONTACT : DATASCIENCE.KM@GMAIL.COM
  2. 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. 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. 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. 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. 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. 7. COMPOSANTS DE SPARK 7 Cluster ManagerSparkContext Spark driver Worker Node Executor TaskTask Worker Node Executor TaskTask Worker Node Executor TaskTask M.MICHRAFY
  8. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 48. DR MUSTAPHA MICHRAFY CONTACT : DATASCIENCE.KM@GMAIL.COM

×