Bases de données
documentaires et distribuées
Traitement de données massives
avec Apache Spark
Auteurs: Raphaël Fournier-S’niehotta, Philippe Rigaux
(fournier@[Link], [Link]@[Link])
Département d’informatique
Conservatoire National des Arts & Métiers, Paris, France
Introduction à Spark 1 / 41
Plan du cours
1 Introduction à Spark
Les RDD
Reprise sur panne
Dataset et Dataframe
Introduction à Spark 2 / 41
Qu’est-ce que Spark?
Spark est un environnement dédié au calcul distribué à grande échelle qui propose
des fonctionnalités bien plus puissantes que le simple MapReduce des origines,
encore disponible dans l’écosystème Hadoop.
Un moteur d’exécution basé sur des opérateurs de haut niveau, comme Pig.
Comprend des opérateurs Map/Reduce, et d’autres opérateurs de second ordre (cf
cours sur Pig)
Introduit un concept de collection résidente en mémoire (RDD) qui améliore
considérablement certains traitements, dont ceux basés sur des itérations
(PageRank, kMeans)
De nombreuses librairies pour la fouille de données (MLib), le traitement des
graphes, le traitement de flux (streaming).
Introduction à Spark 3 / 41
Spark
Initialement développé (2009) par l’AMPlab de l’université de Californie à Berkeley
Transmis à la fondation Apache, développement open-source depuis 2013
plus de 1000 collaborateurs, dont Intel, Facebook, IBM, Netflix
Version actuelle : 3.0 . La version 2.0 a apporté des changements notables
concernant les structures de données utilisées.
Spark est utilisable avec plusieurs langages de programmation : Scala (natif), Java,
Python, R, SQL.
Introduction à Spark Les RDD 3 / 41
Plan du cours
1 Introduction à Spark
Les RDD
Reprise sur panne
Dataset et Dataframe
Introduction à Spark Les RDD 4 / 41
Les limites de MapReduce
la spécification de l’itération reste à la charge du programmeur;
il faut stocker le résultat d’un premier job dans une collection intermédiaire
puis réiterer le job en prenant la collection intermédiaire comme source.
C’est laborieux pour l’implantation, et surtout très peu efficace quand la collection
intermédiaire est grande.
Le processus de sérialisation/désérialisation sur disque propre à la gestion de la
reprise sur panne en MapReduce entraîne des performances médiocres.
Dans Spark, la méthode consiste à placer ces jeux de données en mémoire RAM et à
éviter la pénalité des écritures sur le disque
Le défi est alors bien sûr de proposer une reprise sur panne automatique efficace
Introduction à Spark Les RDD 5 / 41
Les Resilient Distributed Datasets (RDD)
C’est le concept central : Un RDD est une collection (pour en rester à notre vocabulaire)
calculée à partir d’une source de données (MongoDB, un flux, un autre RDD).
Un RDD peut être marqué comme persistant: il est alors placé en mémoire RAM et
conservé par Spark.
Spark conserve l’historique des opérations qui a permis de constituer un RDD, et la
reprise sur panne s’appuie sur cet historique afin de reconstituer le RDD en cas de panne.
L’idée est qu’il est plus facile et efficace de préserver quelques lignes de spécifications que
le jeu de données issu de cette chaîne.
Un RDD est un ”bloc” non modifiable. Si nécessaire il peut-être entièrement recaculé.
Introduction à Spark Les RDD 6 / 41
RDD (suite)
Attention toutefois : un RDD est avant tout partitionné et distribué
il est constitué de fragments
une panne affectant un fragment individuel peut donc être réparée (par
reconstitution de l’historique) indépendamment des autres fragments, évitant d’avoir
à tout recalculer.
un RDD est calculé par une transformation
une transformation sélectionne, enrichit, restructure une collection, ou combine deux
collections
c’est l’équivalent d’un opérateur dans Pig
on retrouve dans Spark, à peu de choses près, les mêmes opérateurs/transformations
que dans Pig
Introduction à Spark Les RDD 7 / 41
Opérateur Description
map Prend un document en entrée et produit un document en
sortie
filter Filtre les documents de la collection
flatMap Prend un document en entrée, produit un ou plusieurs
document(s) en sortie
groupByKey Regroupement de documents par une valeur de clé commune
reduceByKey Réduction d’une paire (k, [v]) par une agrégation du tableau
[v]
crossProduct Produit cartésien de deux collections
join Jointure de deux collections
union Union de deux collections
cogroup Cf. la description de l’opérateur dans la section sur Pig
sort Tri d’une collection
Introduction à Spark Les RDD 8 / 41
Un workflow avec RDD dans Spark
Des transformations (opérateurs comme dans Pig) créent des RDD à partir d’une ou
deux sources de données.
Les RDD persistants sont en préservés en mémoire RAM, et peuvent être réutilisés par
plusieurs traitements.
Introduction à Spark Les RDD 9 / 41
Exemple: analyse de fichiers log
On veut analyser le fichier journal (log) d’une application dont un des modules (M) est
suspect.
On construit un programme qui charge le log, ne conserve que les messsages produits par
le module M et les analyse.
On peut analyser par produit, par utilisateur, par période, etc.
Introduction à Spark Les RDD 10 / 41
Spécification avec Spark
// Chargement de la collection
log = load ("[Link]") as (...)
// Filtrage des messages du module M
logM = filter log with [Link] ("M")
// On rend logM persistant !
[Link]();
Analyse à partir de logM
// Filtrage par produit
logProduit = filter logM with [Link] ("product P")
// .. analyse du contenu de logProduit
Introduction à Spark Reprise sur panne 10 / 41
Plan du cours
1 Introduction à Spark
Les RDD
Reprise sur panne
Dataset et Dataframe
Introduction à Spark Reprise sur panne 11 / 41
Reprise sur panne dans Spark
Un RDD est une collection partitionnée.
Si une panne affecte un calcul s’appuyant sur un fragment F de RDD persistant, il suffit
de le relancer à partir de F .
Si une panne affecte un fragment de RDD persistant, Spark ré-applique la chaîne de
traitement ayant constitué le RDD.
Introduction à Spark Dataset et Dataframe 11 / 41
Plan du cours
1 Introduction à Spark
Les RDD
Reprise sur panne
Dataset et Dataframe
Introduction à Spark Dataset et Dataframe 12 / 41
Des RDD structurés
Un RDD est une ”boîte” (typée) destinée à contenir n’importe quel document,
sans aucun préjugé sur sa structure (ou son absence de structure)
Cela rend le système très généraliste, mais empêche une manipulation fine des
constituants des documents, comme par exemple le filtrage en fonction de la valeur
d’un champ.
C’est au programmeur de fournir la fonction effectuant le filtre.
Spark propose (depuis la version 1.3, avec des améliorations en 1.6 puis 2.0) des
RDD structurés dans lesquels les données sont sous forme tabulaire.
Le schéma de ces données est connu.
Ces structures, Datasets et Dataframes, sont assimilables à des tables relationnelles,
ou à d’autres structures tabulaires (Pandas)
Introduction à Spark Dataset et Dataframe 13 / 41
Des RDD structurés : Dataset et Dataframes
La connaissance du schéma - et éventuellement de leur type - permet à Spark de
proposer des opérations plus fines, et des optimisations inspirées des techniques
d’évaluation de requêtes dans les systèmes relationnels.
On se ramène à une implantation distribuée du langage SQL.
En interne, un avantage important de la connaissance du schéma est d’éviter de
recourir à la sérialisation des objets Java (opération effectuée dans le cas des RDD
pour écrire sur disque et échanger des données en réseau).
Ces RDDs structurés sont nommés :
Dataset quand le type des colonnes est connu,
Dataframe quand ce n’est pas le cas
Un Dataframe n’est rien d’autre qu’un Dataset contenant des lignes de type Row
dont le schéma précis n’est pas connu.
Introduction à Spark Dataset et Dataframe 14 / 41
Un exemple
On souhaite un filtre pour les films dont le genre est ”Drame” :
[Link]([Link]() = "Drame");
Si “films“ est un RDD, Spark n’a aucune idée sur la structure des documents qu’il
contient.
Spark va donc instancier un objet Java (éventuellement en dé-sérialisant une chaîne
d’octets reçue par réseau ou lue sur disque) et appeler la méthode getGenre()
Cela peut être long, et impose surtout de créer un objet pour un simple test.
Avec un Dataset (ou Dataframe), le schéma est connu et Spark utilise son propre
système d’encodage/décodage à la place de la sérialisation Java.
De plus, dans le cas des Dataset, la valeur du champ “genre“ peut être testée
directement sans même effectuer de décodage depuis la représentation binaire.
Introduction à Spark Dataset et Dataframe 15 / 41
Résumé sur les structures de données
Ce cours est encore centré sur les RDDs (API bas niveau), mais il est aujourd’hui
(presque) toujours préférable d’utiliser les API de haut niveau, Dataframes et
Datasets (en raison des optimisations efficaces)
Selon le langage, certaines structures sont indisponibles.
En Scala/Java, typage fort, Dataset[T]
En Python (et autres), typage dynamique, Dataframe
Dataframe = Dataset[Row]
Il existe de nombreux moyens de passer de l’un à l’autre
La plupart des exemples vus s’adaptent assez facilement
Spark en pratique 15 / 41
Plan du cours
2 Spark en pratique
Scala
Premier RDD
Un compteur de termes
L’interface de contrôle Spark
Spark en pratique Scala 15 / 41
Plan du cours
2 Spark en pratique
Scala
Premier RDD
Un compteur de termes
L’interface de contrôle Spark
Spark en pratique Scala 16 / 41
Scala
c’est le langage natif de Spark.
concilie programmation orientée objet ET programmation fonctionnelle
compilé en bytecode Java, peut utiliser les bibliothèques Java de façon transparente
syntaxe plus concise que le Java
object HelloWorld {
def main(args: Array[String]) {
println("Hello, world!")
}
}
Spark en pratique Scala 17 / 41
Installation de Spark
[Link]
télécharger une archive
décompresser (tar -xvzf ...)
lancer l’interpréteur de commandes spark-shell
Spark en pratique Scala 18 / 41
Gérer les messages d’erreurs
$ cp sparkdir/conf/[Link] sparkdir/conf/[Link]
$ kwrite [Link]
# remplacer INFO par WARN dans [Link]=INFO
$ export SPARK_HOME=<votre sparkdir>
Spark en pratique Premier RDD 18 / 41
Plan du cours
2 Spark en pratique
Scala
Premier RDD
Un compteur de termes
L’interface de contrôle Spark
Spark en pratique Premier RDD 19 / 41
Le retour des loups et des moutons
Téléchargez [Link]
ouvrez-le
chargez-le dans spark
scala> val loupsEtMoutons = [Link]("[Link]")
loupsEtMoutons: [Link][String] = [Link] MapPartitionsRDD[1] at textFile
,→ at <console>:27
Spark en pratique Premier RDD 19 / 41
Le retour des loups et des moutons
Téléchargez [Link]
ouvrez-le
chargez-le dans spark
scala> val loupsEtMoutons = [Link]("[Link]")
loupsEtMoutons: [Link][String] = [Link] MapPartitionsRDD[1] at textFile
,→ at <console>:27
Attention : spécifiez le bon chemin !
Spark en pratique Premier RDD 20 / 41
Premières actions
scala> [Link]() // Nombre de documents dans ce RDD
res2: Long = 4
Remarque : le résultat est stocké dans une variable appelée res2. Il est bien entendu
préférable de donner vous-mêmes des noms porteurs de sens à vos variables.
Spark en pratique Premier RDD 20 / 41
Premières actions
scala> [Link]() // Nombre de documents dans ce RDD
res2: Long = 4
Remarque : le résultat est stocké dans une variable appelée res2. Il est bien entendu
préférable de donner vous-mêmes des noms porteurs de sens à vos variables.
scala> val premiereLigne = [Link]() // Premier élément du RDD
premiereLigne: String = Le loup est dans la bergerie.
Remarque : Le type de la variable a été inféré par Scala (String).
Spark en pratique Premier RDD 20 / 41
Premières actions
scala> [Link]() // Nombre de documents dans ce RDD
res2: Long = 4
Remarque : le résultat est stocké dans une variable appelée res2. Il est bien entendu
préférable de donner vous-mêmes des noms porteurs de sens à vos variables.
scala> val premiereLigne = [Link]() // Premier élément du RDD
premiereLigne: String = Le loup est dans la bergerie.
Remarque : Le type de la variable a été inféré par Scala (String).
scala> [Link]() // Récupération du RDD complet
res4: Array[String] = Array(Le loup est dans la bergerie., Les moutons sont dans la bergerie., Un
,→ loup a mangé un mouton, les autres loups sont restés dans la bergerie., Il y a trois moutons
,→ dans le pré, et un mouton dans la gueule du loup.)
Spark en pratique Premier RDD 21 / 41
Des transformations
Une transformation prend un (ou deux) RDD en entrée et produit un RDD en sortie.
Spark en pratique Premier RDD 21 / 41
Des transformations
Une transformation prend un (ou deux) RDD en entrée et produit un RDD en sortie.
On peut sélectionner les documents qui contiennent ”bergerie”.
scala> val bergerie = [Link](line => [Link]("bergerie"))
bergerie: [Link][String] = MapPartitionsRDD[7] at filter at <console>:29
On utilise ici un paradigme fréquent en Spark/scala : une fonction anonyme, comme
paramètre d’une autre fonction.
contains() renvoie True ou False, selon que la chaîne (ligne) contient ”bergerie” ou
non. Filter() ne conserve que les lignes pour lesquelles True a été renvoyé.
bergerie est un RDD, dont les éléments sont des String.
pour le moment, il n’y a pas eu d’actions : bergerie n’a pas été calculé (il y a eu
quelques vérifications de compilations, pas de chargement de données).
Spark en pratique Premier RDD 22 / 41
C’est la première action qui déclenche l’exécution de la chaîne de traitement. Par
exemple, un collect (sur des grandes collections, utilisez plutôt un first ou take(10))
scala> [Link]()
res9: Array[String] = Array(Le loup est dans la bergerie., Les moutons sont dans la
,→ bergerie., Un loup a mangé un mouton, les autres loups sont restés dans la bergerie.)
On peut combiner une transformation et une action. En fait, avec Scala, on peut
chaîner les opérations et ainsi définir très concisément le workflow :
scala> [Link](line => [Link]("loup")).count()
res5: Long = 3
Spark en pratique Un compteur de termes 22 / 41
Plan du cours
2 Spark en pratique
Scala
Premier RDD
Un compteur de termes
L’interface de contrôle Spark
Spark en pratique Un compteur de termes 23 / 41
Compteur de termes
on crée le RDD avec tous les termes, en découpant chaque ligne (aux espaces, en
première approximation) :
scala> val termes = [Link](line => [Link](" "))
Notez l’opérateur “flatMap“ qui produit plusieurs documents (ici un terme) pour un
document en entrée (ici une ligne).
Spark en pratique Un compteur de termes 23 / 41
Compteur de termes
on crée le RDD avec tous les termes, en découpant chaque ligne (aux espaces, en
première approximation) :
scala> val termes = [Link](line => [Link](" "))
Notez l’opérateur “flatMap“ qui produit plusieurs documents (ici un terme) pour un
document en entrée (ici une ligne).
On crée un nouveau RDD, dans lequel chaque élément est remplacé par une paire,
composée de cet élément, associé à la valeur 1.
scala> val termeUnit = [Link](word => (word, 1))
Spark en pratique Un compteur de termes 23 / 41
Compteur de termes
on crée le RDD avec tous les termes, en découpant chaque ligne (aux espaces, en
première approximation) :
scala> val termes = [Link](line => [Link](" "))
Notez l’opérateur “flatMap“ qui produit plusieurs documents (ici un terme) pour un
document en entrée (ici une ligne).
On crée un nouveau RDD, dans lequel chaque élément est remplacé par une paire,
composée de cet élément, associé à la valeur 1.
scala> val termeUnit = [Link](word => (word, 1))
On passe à l’opérateur une fonction de réduction, ici notée littéralement dans la
syntaxe Scala (si j’ai deux valeurs, j’en fait la somme).
scala> val compteurTermes = [Link]((a, b) => a + b)
Spark en pratique Un compteur de termes 24 / 41
On aurait pu tout faire en une fois !
scala> val compteurTermesUneFois = [Link](line => [Link](" "))
.map(word => (word, 1))
.reduceByKey((a, b) => a + b)
Il reste à exécuter le traitement.
scala> [Link]()
scala> [Link]()
Remarquez les incohérences, liées au découpage seulement aux espaces, sans avoir
enlevé la ponctuation.
Spark en pratique Un compteur de termes 25 / 41
Bonus
Afficher le top 10 des éléments les plus fréquents
1 val sorted = [Link](_._2,false)
2 [Link]().take(10).foreach(println)
Spark en pratique L’interface de contrôle Spark 25 / 41
Plan du cours
2 Spark en pratique
Scala
Premier RDD
Un compteur de termes
L’interface de contrôle Spark
Spark en pratique L’interface de contrôle Spark 26 / 41
Spark dispose d’une interface Web qui permet de consulter les entrailles du système
et de mieux comprendre ce qui est fait.
Elle est accessible sur le port 4040, donc à l’URL [Link] si vous
travaillez localement (vérifiez les messages au lancement de votre shell, parfois
l’adresse ou le port changent)
:paste // pour pouvoir coller plusieurs commandes
var compteurTermes = [Link]("[Link]")
.flatMap(line => [Link](" "))
.map(word => (word, 1))
.reduceByKey((a, b) => a + b)
[Link]()
Spark en pratique L’interface de contrôle Spark 26 / 41
Spark en pratique L’interface de contrôle Spark 27 / 41
Spark en pratique L’interface de contrôle Spark 27 / 41
Explications
Il y a 2 étapes (stages), stage0, stage1
une étape dans Spark regroupe un ensemble d’opérations qu’il est possible
d’exécuter sur une seule machine
C’est une généralisation de la phase de *Map* dans un environnement MapReduce
une étape est effectuée en parallèle sur les différents fragments de nos données
Spark appelle tâche l’exécution de l’étape sur un fragment particulier
la séquence des étapes constitue un job.
Spark en pratique L’interface de contrôle Spark 28 / 41
Les autres onglets
Regardez aussi les onglets Stages et Storage
nombreuses statistiques sur le temps d’exécution, volume de données, etc.
Onglet storage vide
[Link]()
[Link]()
Spark en pratique L’interface de contrôle Spark 29 / 41
Exercices
À vous de jouer. Refaites ces expériences à l’aide du support de cours, pour explorer
Spark et vous familiariser avec son fonctionnement.
Traitement de données structurées avec Cassandra et Spark 29 / 41
Plan du cours
3 Traitement de données structurées avec Cassandra et Spark
Traitements basés sur les Datasets
Exercices
Traitement de données structurées avec Cassandra et Spark 30 / 41
Lions Spark avec Cassandra
On va voir une première utilisation de la liaison entre Spark et Cassandra
Cassandra contient les données, Spark les traite
cela correspond à un scénario classique de traitement des données
on va utiliser les Dataset plutôt que les simples RDD
Spark saura optimiser certains traitements (et valider à la compilation, et non à
l’exécution)
en tant que concepteur, travailler sur un schéma de données est souvent plus facile
(code plus lisible)
en terme d’architecture, chaque nœud Spark traite un ou plusieurs fragments d’une
collection partitionnée Cassandra, et communique donc avec un des nœuds de la
grappe Cassandra
Traitement de données structurées avec Cassandra et Spark 31 / 41
La base Cassandra des Restaurants new-yorkais
On reprend la création de la base Cassandra vue en TP
CREATE KEYSPACE IF NOT EXISTS resto_NY WITH REPLICATION = { 'class' : 'SimpleStrategy',
,→ 'replication_factor': 1};
USE resto_NY;
CREATE TABLE Restaurant ( id INT, Name VARCHAR, borough VARCHAR, BuildingNum VARCHAR, Street
,→ VARCHAR, ZipCode INT, Phone text, CuisineType VARCHAR, PRIMARY KEY ( id )) ;
CREATE INDEX fk_Restaurant_cuisine ON Restaurant ( CuisineType ) ;
CREATE TABLE Inspection ( idRestaurant INT, InspectionDate date, ViolationCode VARCHAR,
,→ ViolationDescription VARCHAR, CriticalFlag VARCHAR, Score INT, GRADE VARCHAR, PRIMARY KEY
,→ ( idRestaurant, InspectionDate ) ) ;
Ou, mieux, on se connecte à la base de la salle de cours (IP: [Link], port
9042)
Traitement de données structurées avec Cassandra et Spark 32 / 41
Associer Spark et Cassandra
Pour associer Spark et Cassandra, il faut récupérer le connecteur sur la page
[Link]
Prenez la version la plus récente, en tout cas celle correspondant à votre version de
Spark.
Lancer le Spark-shell avec ces paramètres :
1 spark-shell --packages datastax:spark-cassandra-connector:1.6.10-s_2.11
Puis intégrez les paramètres de Cassandra dans Spark
import [Link]._
import [Link]
import [Link]
// Paramètres de connexion
[Link]("default",
[Link]("[Link]")
++ [Link](32769))
Traitement de données structurées avec Cassandra et Spark 33 / 41
Vérifions
val restaurants_df = [Link]("restaurant", "resto_ny").load()
restaurants_df.printSchema()
restaurants_df.show()
Il semble que le nom du *Keyspace* et de la table doivent être mis en minuscules.
le schéma (le nom des colonnes) du Dataset est obtenu depuis Cassandra
les colonnes ne sont pas typées
Traitement de données structurées avec Cassandra et Spark 34 / 41
Pour des colonnes typées
On définit directement une classe Scala, et on demande la conversion des données
case class Restaurant(id: Integer, Name: String, borough: String,
BuildingNum: String, Street: String,
ZipCode: Integer, Phone: String, CuisineType: String)
val restaurants_ds = restaurants_df.as[Restaurant]
on dispose de deux structures Dataset :
restaurant_df, de type Dataframe, collection d’objets de type Row
restaurant_ds, de type Datasetn collection d’objets de type Restaurant
le second permettra des opérations plus fines
Traitement de données structurées avec Cassandra et Spark 35 / 41
Pause réflexion
Compromis à garder en mémoire : vaut-il mieux
des données au schéma très contraint mais offrant plus de sécurité
des données au schéma très flexible, mais beaucoup plus difficile à manipuler
La réponse, bien entendu, dépend du contexte. Mais du temps passé en amont n’est pas
forcément du temps perdu en aval du projet.
Traitement de données structurées avec Cassandra et Spark 36 / 41
Les inspections
Nous aurons également besoin des données sur les inspections de ces restaurants.
case class Inspection (idRestaurant: Integer, InspectionDate: String, ViolationCode: String,
,→ ViolationDescription: String, CriticalFlag: String, Score: Integer, Grade: String)
val inspections_ds = [Link]("inspection",
,→ "resto_ny").load().as[Inspection]
Traitement de données structurées avec Cassandra et Spark Traitements basés sur les Datasets 36 / 41
Plan du cours
3 Traitement de données structurées avec Cassandra et Spark
Traitements basés sur les Datasets
Exercices
Traitement de données structurées avec Cassandra et Spark Traitements basés sur les Datasets 37 / 41
Projections
Une projection, consiste à ne conserver que certaines colonnes
c’est le mal-nommé select du SQL
val restaus_simples = restaurants_ds.select("name", "phone", "cuisinetype")
restaus_simples.show()
Traitement de données structurées avec Cassandra et Spark Traitements basés sur les Datasets 38 / 41
Sélection
C’est l’opérateur filter, que l’on a vu précédemment, que l’on utilise
voir le where du SQL
val manhattan = restaurants_df.filter("borough = 'MANHATTAN'")
[Link]()
Traitement de données structurées avec Cassandra et Spark Traitements basés sur les Datasets 39 / 41
Tirons parti des Datasets
On peut profiter du fait que l’on a affaire à une collection d’objets de type Restaurant
on travaille directement sur un tel objet et ses attributs
il y a un typage statique (vérification à la compilation qu’il n’y aura pas de problème
à l’exécution)
val r = restaurants_ds.filter(r => [Link] == "MANHATTAN")
Traitement de données structurées avec Cassandra et Spark Traitements basés sur les Datasets 40 / 41
Agrégats
Regroupons les restaurants par arrondissement (borough)
val comptage_par_borough = [Link]("borough").count()
on aurait pu faire ça en CQL.
Traitement de données structurées avec Cassandra et Spark Traitements basés sur les Datasets 40 / 41
Agrégats
Regroupons les restaurants par arrondissement (borough)
val comptage_par_borough = [Link]("borough").count()
on aurait pu faire ça en CQL.
Mais Spark nous propose la jointure, qui manque à CQL…
val restaus_inspections = restaurants_ds
.join(inspections_ds, restaurants_ds("id") === inspections_ds("idRestaurant"))
Traitement de données structurées avec Cassandra et Spark Traitements basés sur les Datasets 40 / 41
Agrégats
Regroupons les restaurants par arrondissement (borough)
val comptage_par_borough = [Link]("borough").count()
on aurait pu faire ça en CQL.
Mais Spark nous propose la jointure, qui manque à CQL…
val restaus_inspections = restaurants_ds
.join(inspections_ds, restaurants_ds("id") === inspections_ds("idRestaurant"))
Terminons par le calcul du meilleur restaurant de Tapas :
val restaus_stats = restaurants_ds.filter("cuisinetype > 'Tapas'")
.join(inspections_ds, restaurants_ds("id") === inspections_ds("idRestaurant"))
.groupBy(restaurants_ds("name"))
.agg(avg(inspections_ds("score")))
Traitement de données structurées avec Cassandra et Spark Exercices 40 / 41
Plan du cours
3 Traitement de données structurées avec Cassandra et Spark
Traitements basés sur les Datasets
Exercices
Traitement de données structurées avec Cassandra et Spark Exercices 41 / 41
Exercices
Refaites ce que l’on vient de voir
Avec l’interface Web regardez les plans d’exécution