Bases de Données / Databases

Site Web de l'équipe BD du LIP6 / LIP6 DB Web Site

Outils pour utilisateurs

Outils du site


site:enseignement:master:bdle:tmes:tme3-scala

[Pré-requis] Introduction à Scala

Remarque générale : Le cours ne peut être self-contained –> consulter la documentation en ligne de Spark.

Exercice 1

Cet exercice illustre les différentes structures de contrôle de Scala présentées en cours. Il permet de comprendre le paradigme fonctionnel : seules les fonctions map, reduce, flatten, filter, flatMap sont autorisées.

Lancer le spark-shell en mode local (voir Doc). Répondre aux questions ci-dessous.

Question 1

  • Définir la fonction maxEntiers qui retourne le plus grand des entiers d'une liste fournie en entrée.
  • Définir la fonction scEntiers qui calcule la somme des carrés des entiers d'une liste fournie en entrée.
  • Définir la fonction moyEntiers qui calcule la moyenne des entiers d'une liste fournie en entrée.

Tester au fur et à mesure ces fonctions sur listeEntiers construit comme suit :

val listeEntiers = List.range(1,11)

Réponse

def maxEntiers(in: List[Int])= in.reduce((a,b)=>(if(a>b)a else b))
def scEntiers(in: List[Int])= in.map(e=>e*e).reduce((a,b)=>(a+b))
def moyEntiers(in: List[Int])={val p = in.map(e=>(1,e)).reduce((a,b)=>(a._1+b._1, a._2+b._2)); p._2/p._1}

Question 2

Soit une liste chaine de caractères construite à l'aide de l'instruction suivante

val listeTemp = List("7,2010,04,27,75", "12,2009,01,31,78", "41,2009,03,25,95", "2,2008,04,28,76", "7,2010,02,32,91")

Chaque élément représente un enregistrement fictif de températures avec le format (station, année, mois, température, code_département).

  • Calculer pour l'année 2009 le maximum de ses températures.
  • Idem pour la moyenne de ces température.

Bien entendu, il faudra faire les transformations et les conversions de type nécessaires!

Réponse

val temp2009 = listeTemp.map(x=>x.split(",")).filter(_(1).toInt==2009).map(x=>x(3).toInt)
maxEntiers(temp2009)
moyEntiers(temp2009)

Question 3

Soit une liste chaine de caractères construite à l'aide de l'instruction suivante

val melange = List("1233,100,3,20171010", "1224,22,4,20171009", "100,lala,comedie", "22,loup,documentaire")

Deux types d'éléments existent : ceux de la forme (userID, movieID, rating, timestamp) et ceux de la forme (movieID, title, genre). Le domaine des userID est [1000, 2000] et celui des movieID est [0, 100].

Il est demandé de construire à partir de melange deux listes distinctes :

  • notes contenant les éléments de la forme (userID, movieID, rating, timestamp) et dont le type est (Int, String, Int, Int) ;
  • films contenant les éléments de la forme (movieID, title, genre) et dont le type est (Int, String, String).

Réponse

val notes = melange.map(_.split(",")).filter(_(0).toInt>=1000).map(x=>(x(0).toInt,x(1), x(2).toInt, x(3).toInt))
val films = melange.map(_.split(",")).filter(_(0).toInt<=100).map(x=>(x(0).toInt,x(1), x(2)))

Question 4

Soit une liste personnes contenant des tuples ayant trois attributs décrivant des personnes :

  • le premier attribut est le nom de la personne;
  • le second attribut est le type de la personne : etudiant (etu), enseignant (ens) ou inconnu (nan);
  • la troisième attribut est l'année d'inscription (s'il s'agit d'un étudiant) ou les années d'ancienneté pour

les enseignants.

val personnes = List(("Joe", "etu", 3), ("Lee", "etu", 4), ("Sara", "ens", 10), ("John", "ens", 5), ("Bill", "nan",20))
  1. Définir une classe Etu(nom:String, annee:Int) et une classe Ens(nom:String, annee:Int)
  2. Transformer personnes en une liste d'objets de la classe Etu ou Ens encapsulant les information des tuples

en entrée. Par exemple, le tuple (“Joe”, “etu”, 3) devra être transformé en un objet Etu(“Joe”, 3).

Attention Les personnes de type inconnu ne doivent être dans le résultat!

Astuce Utiliser le pattern matching

Réponse

val personnes = List(("Joe", "etu", 3), ("Lee", "etu", 4), ("Sara", "ens", 10), ("John", "ens", 5), ("Bill", "eng",20))
class Etu(nom:String, annee:Int){override def toString()="Etudiant en " +annee+" annee"}
class Ens(nom:String, annee:Int){override def toString()="Enseignant avec " +annee+" annee d'experience"}
val classes_personnes = personnes.map(x=> x match { case(a,"ens",b) =>new Ens(a,b); case(a, "etu", b) =>new Etu(a,b); case _=>None}).filter(_!=None)

Exercice 2

Commencer par copier et décompresser dans votre espace de travail le fichier

/Infos/bd/spark/bdle/2015/data/wordcount.txt.bz2

Le fichier obtenu, wordcount.txt (45Mo), contient des statistiques d’accès aux pages Wikimdia en différentes langue. Une ligne de la forme En.d updates 3 24145 indique dans une page écrite en anglais (symbole ‘En’), intitulée ‘updates’ qui a été cliqué 3 fois et qui fait 24145 octets.

Lancer le spark-shell en mode local (voir Doc) en suivant les instructions fournies puis charger le fichier

 wordcount.txt 

au moyen de la méthode textFile() invoquée à partir de la variable context comme suit :

 val data = sc.textFile("<le_chemin_dans_votre_espace_perso>/wordcount.txt")

Ici, la variable data est une RDD, et donc, de type Array tel que vous pouvez le constater sur le shell. L’invocation de la méthode take(n) sur cette variable affiche les n premiers éléments sur une seule ligne. Pour un affichage sur plusieurs lignes (tel un head -n sous linux), utiliser plutôt take(n).foreach(println) qui itère sur les éléments de la variable d’où elle est invoquée et affiche chaque élément sur une ligne séparément. Noter également que la méthode count retourne la cardinalité (nombre d’éléments) de la RDD d’où elle est invoquée. Par soucis de lisibilité de votre code, stocker le résultat de chaque question dans des variables nommées q1, q2, q3 etc. Penser à tester au fur et à mesure le résultat des instructions lorsque celles-ci ne contiennent que des transformations.

Manipulation de RDDs Simples

  1. Extraire le 4e champ de chaque élément de data et le convertir en type double
  2. Construire à partir de q1 une liste contenant les nombres compris strictement entre 1000 et 1300 puis convertir en type entier.
  3. Construire à partir de q2 une liste contenant les multiples de 3 et l’appeler q33. Faire de même pour les multiples de 4 et l’appeler q34.
  4. Construire une liste obtenue en divisant par 10 chaque élément de q33.
  5. Construire à partir de q4 un ensemble d’éléments (liste sans doublons).Construire une liste contenant les éléments de q2 qui sont multiples de 3 et de 4 à la fois. Utiliser impérativement q33 et q34.
  6. Construire une liste contenant les éléments de q2 qui sont multiples de 3 mais pas de 4. Utiliser impérativement q33 et q34.
  7. Construire à partir de q2 une liste contenant les éléments de q2 multiples de 3 ou de 10. Mettre les résultats dans la variable q8.
  8. Convertir les éléments de q8 en type Double puis calculer la somme (q9sum), le minium (q9min) ainsi que le maximum (q9max) des éléments de q8. Calculer la moyenne (q9avg) en utilisant un operateur parmi reduce, fold et aggregate.
  9. Retourner pour chaque élément distinct de q2 le nombre de fois qu’il apparaît dans cette liste.

Réponse

//1.	Extraire dans une variable appelée listEnt le 4e champ de chaque élément de data.
val q1 = data.map(x=>x.split(" ")).map(x=>x(3).toDouble)
 
 
//2.	Construire à partir de q1 une liste contenant les nombres compris strictement entre 1000 et 1300 puis convertir en type entier.
 
val q2 = q1.filter(x=> x>1000 && x<1300 )map(x=>x.toInt)
 
 
//.	Construire à partir de q2 une liste contenant les multiples de 3 et l’appeler q33. Faire
 
val q33 = q2.filter(x=>x%3==0)
val q39 = q2.filter(x=>x%9==0)
 
//4.	Construire une liste obtenue en divisant par 10 chaque élément de q33.
 
val q4 = q33.map(x=>x/10)
 
//5.	Construire à partir de q4 un ensemble d’éléments (liste sans doublons).
 
val q5 = q4.distinct
 
 
//6.	Construire à partir de q2 une liste contenant ses qui sont multiples de 3 et de 9 à la fois. Utiliser impérativement q33 et q39. 
 
val q6 = q33.intersection(q39)
 
 
//7.	Construire à partir de q2 une liste contenant ses éléments qui sont multiples de 3 mais pas de 9. Utiliser impérativement q33 et q39. 
 
val q7 = q33.subtract(q39)
 
//8.	Construire à partir de q2 une liste contenant ses  éléments qui sont multiples de 3 ou de 10.
 
val q8 = q33.union(q2.filter(x=>x%3==0))
 
//9.	Calculer la somme,  la moyenne, le minium ainsi que le maximum des éléments de q8. 
 
val q9sum = q8.map(x=>x.toDouble).reduce(_+_)
 
val q9max = q8.map(x=>x.toDouble).reduce((x,y)=>if (x > y) x else y)
 
val q9min = q8.map(x=>x.toDouble).reduce((x,y)=>if (x < y) x else y)
 
val q9avg = q8.map(x=>(x,1)).reduce((x,y)=>(x._1+y._1,x._2+y._2))
 
q9avg._1/q9avg._2
site/enseignement/master/bdle/tmes/tme3-scala.txt · Dernière modification: 01/10/2018 12:39 par amine