spark hands-on

79
Spark hands-on

Upload: gaspar-munoz-soria

Post on 08-Jan-2017

925 views

Category:

Data & Analytics


0 download

TRANSCRIPT

Page 1: Spark Hands-on

Spark hands-on

Page 2: Spark Hands-on

Jorge López-Malla [email protected]

CONTACTO Gaspar Muñ[email protected]

Introducción

● Introducción al Big Data

● Hadoop

● ¿Por qué Spark?

1

4

Conceptos de Spark

● RDD - Dataframe - DStream

● Componentes de un clúster

● Despliegue de Spark

2

5

3

6Spark SQL

● Introducción

● Dataframe API

● Datasources

● Ejemplos prácticos y Ejercicios

Spark core

● Transformaciones

● Acciones

● Variables compartidas

● Ejemplos prácticos y Ejercicios

Spark Streaming

● Receivers

● Operaciones con DStreams

● Operaciones con ventanas

● Operaciones “Stateful”

MlLib

● Introducción

● Algoritmos

● Ejemplos prácticos

Page 3: Spark Hands-on

Quienes somos

Tras trabajar con algunas

metodologías tradicionales

empecé a centrarme en el

mundo del Big Data, del cual

me enamoré. Ahora soy

arquitecto Big Data en Stratio y

he puesto proyectos en

producción en distintas partes

del mundo.

Page 4: Spark Hands-on

Quienes somos

Arquitecto Big Data y

desarrollador en Stratio desde

su creación. He trabajado en

multitud de exitosos proyectos

con Hadoop, Spark y todo su

ecosistema.

Page 5: Spark Hands-on
Page 6: Spark Hands-on

[email protected] [email protected]

Page 7: Spark Hands-on

Introducción al Modelo de Map & Reduce

Page 8: Spark Hands-on

Introducción al Modelo de Map & Reduce

Map&Reduce es un modelo de programación utilizado por Google para dar soporte a la computación

paralela sobre grandes colecciones de datos en grupos de computadoras y al commodity computing. El

nombre del framework está inspirado en los nombres de dos importantes métodos, macros o funciones

en programación funcional: Map y Reduce. MapReduce ha sido adoptado mundialmente, ya que existe

una implementación OpenSource denominada Hadoop. Su desarrollo fue liderado inicialmente por

Yahoo y actualmente lo realiza el proyecto Apache. En esta década de los años 2010 existen diversas

iniciativas similares a Hadoop tanto en la industria como en el ámbito académico, entre ellas está Spark.

Page 9: Spark Hands-on

Introducción al Modelo de Map & Reduce

Map(k1,v1) -> list(k2,v2) Reduce(k2,list(v2)) -> (k3,v3)

Page 10: Spark Hands-on

Introducción al Modelo de Map & Reduce

Fases opcionales del modelo

Aunque el modelo Map & Reduce puede realizarse únicamente con las fases de Map y de Reduce existen una serie de fases

opcionales que nos ayudan a mejorar y optimizar nuestros procesos. Estas fases son:

● Combiner (Fase de Combinación)

● Partitioner (Fase de Particionado)

Map Combiner Partitioner Reduce

Page 11: Spark Hands-on

Introducción al Modelo de Map & Reduce

Apache Hadoop es un framework de procesamiento y almacenamiento distribuido que facilita la

programación de tareas mediante el paradigma map & reduce y es escalable desde unos pocos hasta miles de

nodos. Es bastante robusto y está diseñado para trabajar en alta disponibilidad, con tolerancia a fallos y en su

versión reciente gestionar recursos de manera muy eficiente.

Page 12: Spark Hands-on

Introducción al Modelo de Map & Reduce

Page 13: Spark Hands-on

Introducción al Modelo de Map & Reduce

Apache Spark es una framework de procesamiento distribuido en memoria de segunda

generación que facilita la analítica de grandes conjuntos de datos integrando diferentes

paradigmas como Bases de Datos NoSQL, analítica en tiempo real, machine learning o análisis de

grafos mediante un único lenguaje común.

SPARK CORE

SQL RSTREAMING MlLib GraphX

Page 14: Spark Hands-on

Introducción al Modelo de Map & Reduce

Page 15: Spark Hands-on
Page 16: Spark Hands-on

[email protected] [email protected]

Spark core

Page 17: Spark Hands-on

Definición:

Un RDD en Spark es una colección de colecciones de objetos inmutable y distribuida. Cada RDD está dividido en diferentes particiones, que

pueden ser computadas en los distintos nodos del Cluster de Spark.

Es la Unidad mínima de computación en Spark

Ej:

El RDD numbers es un rdd de enteros que está distribuido por en un cluster con 3 Workers{W1, W2, W3}

numbers = RDD[1,2,3,4,5,6,7,8,9,10]

Conceptos de Spark

W1 W2 W2

[1,5,6,9] [2,7,8] [3,4,10]

Page 18: Spark Hands-on

Definición:

Un DStream representa una corriente de datos, un conjunto de datos que llegan de manera continua desde una fuente. En Spark este

concepto se implementa como “micro batchs” de RDDs.

Es la unidad mínima de procesamiento de Spark Streaming

Ej:

Conceptos de Spark

DStream

R

D

D

R

D

D

R

D

D

R

D

D

R

D

D

R

D

D

R

D

D

R

D

D

Page 19: Spark Hands-on

Definición:

Un DataFrame en Spark es una colección de colecciones de objetos inmutable y distribuida organizada en columnas con nombre.

Conceptualmente es igual que una tabla en una base de datos relacional. Estos datos pueden provenir de muchas fuentes de datos

estructurados como Json, CSV, tablas de Hive u otros RDD existentes

Es la Unidad mínima de computación en Spark SQL

Ej:

El RDD persons es un Dataframe que representa la tabla persona que tiene un campo nombre, texto, y otro campo edad, un entero.

Conceptos de Spark

W1 W2 W3

[Jorge, 31] [Gaspar, 28] [María 23]

persons= Dataframe[(Jorge, 31);

(Gaspar, 28);

(María, 23)]

Nombre -> String; Edad -> Int

Page 20: Spark Hands-on

Spark se puede desplegar de distintas maneras:

● Local: Levanta un cluster embebido de Spark.○ Se hace creando un SparkContext con master = local[NumeroCores]○ El SparkMaster se levanta en el propio proceso y no es accesible ni por via web○ Los Workers, tantos como NúmeroCores, se levantan también en el propio proceso (página de stages accesible vía Web)

● Standalone:○ El SparkMaster se lanza en una máquina del cluster. Web en el Master○ Tendrá tantos Workers como máquinas se indiquen en el fichero slaves○ Se despliega mediante el script start-all.sh de Spark.

Conceptos de Spark

Page 21: Spark Hands-on

Spark se puede desplegar de distintas maneras:

● YARN○ Se usa el gestor de recursos de Hadoop YARN○ Nuestra aplicación de Spark se lanza dentro de un contenedor de Yarn, que es el encargado de dar los recursos○ Podemos tener varios SparkMaster corriendo a la vez en el cluster (ojo NO podrán compartir información)

● Mesos:○ Mesos es otro gestor de recursos, Spark fue uno de sus Casos de uso○ Como con YARN puede haber más de un SparkMaster (tampoco se podrá compartir su información)○ Se usaba con frecuencia en el primeros momentos de spark, ahora se usa con menos frecuencia.

Conceptos de Spark

Page 22: Spark Hands-on
Page 23: Spark Hands-on

[email protected] [email protected]

Page 24: Spark Hands-on

Los RDD tienen dos tipos de operaciones:

1. Transformaciones: Son aquellas operaciones que tras ejecutarlas nos devuelven otro RDD. Como un RDD no deja de ser una colección

distribuida estas operaciones son Lazy por lo que no se realizará ningún cálculo a no ser que al final del árbol de operaciones haya una

acción.

2. Acciones: Son operaciones que una vez realizadas sobre un RDD nos devuelven un objeto distinto a un RDD o vacío. Este tipo de

operaciones hace que se lance la ejecución del workflow y por consiguiente que se ejecute nuestra aplicación de Spark.

Spark Core

Page 25: Spark Hands-on

Spark Core

map

Devuelve el rdd resultante de aplicar una función a cada uno de los elementos del rdd que lo invoca:

map(f: (V) ⇒ U) : RDD[U]

map

scala> val rddUpper = rddCow.map(_.toUpperCase)

rddUpper: org.apache.spark.rdd.RDD[String] = MappedRDD[1] at map

rddCow rddUpper

I've never seen a purple cow

I never hope to see one

But i can tell you, anyhow,

I’d rather see than be one

I'VE NEVER SEEN A PURPLE COW

I NEVER HOPE TO SEE ONE

BUT I CAN TELL YOU, ANYHOW,

I’D RATHER SEE THAN BE ONE

Page 26: Spark Hands-on

Spark Core

flatMap scala> val rddCowWords = rddCow.flatMap(_.split(" "))

rddCowWords: org.apache.spark.rdd.RDD[String] = FlatMappedRDD[2] at flatMap

scala> rddCow.partitions.size == rddCowWords.partitions.size

res1: Boolean = true

scala> rddCow.count == rddCowWords.count

25/04/15 10:30:28 INFO SparkContext: Starting job: count

25/04/15 10:30:28 INFO DAGScheduler: Got job 2 (count) with 3 output partitions

(allowLocal=false)

25/04/15 10:30:20 INFO DAGScheduler: Job 3 finished: count, took 0,11456 s

res2: Boolean = false

flatMap

rddCowWords

I've never seen a purple cow

I never hope to see one

But i can tell you, anyhow,

I’ve

never

seen

a

purple

cow

I

never

hope

to

see

one

But

i

can

tell

you,

anyhow

rddCow

Page 27: Spark Hands-on

Spark Core

filter scala> val rddEven = rddNumber.filter(number => number%2 == 0)

rddEven : org.apache.spark.rdd.RDD[Int] = FlatMappedRDD[3] at filter

scala> rddNumber.partitions.size == rddEven.partitions.size

res3: Boolean = true

scala> rddNumber.count == rddEven.count

25/11/15 11:30:28 INFO SparkContext: Starting job: count

25/11/15 11:30:28 INFO DAGScheduler: Got job 2 (count) with 3 output partitions (allowLocal=false)

25/11/15 11:30:20 INFO DAGScheduler: Job 3 finished: count, took 0,11456 s

res4: Boolean = false

filter

rddEven

1

2

3

rddNumber

2

Page 28: Spark Hands-on

join:

Spark Core

(Algebra, prof1)

(Calculus, prof2)

(Sw Engineering , prof2)

(Algebra, alumn1)

(Logic, alumn1)

(Algebra, alum3)

(Algebra, alum2)

(Calculus, alum1)

(Calculus, alum2)

(Algebra, alum4)

(Algebra, (prof1,alumn1)

(Algebra, (prof1, alum3)

(Algebra, (prof1, alum2))

(Algebra, (prof1, alum4))

(Calculus, (prof2, alum2))

(Calculus, (prof2, alum1))

rddCourseTeacher

rddCourseStudent

rddCourseTeacherStudent

scala> val rddCourseTeacherAllStudent = rddCourseTeacher.leftOuterJoin(rddCourseStudent)

rddCourseTeacherStudent: org.apache.spark.rdd.RDD[(String,(Int, Int))] =

FlatMappedValuesRDD[1] at join

join

Page 29: Spark Hands-on

groupByKey:

Agrupa los valores por una clave devolviendo una lista por cada clave

groupByKey() : RDD[(K,Iterable[V])]

Spark Core

(odd, 3)

(odd, 3)

(odd, 5)

(even, 12)

(even, 4)

(even, 4)

groupByKey

(odd, (3, 3, 5))

(even, (4, 4, 12)

rddIsEvenNumber

rddIsEvenNumbers

scala> val rddIsEvenNumbers = rddIsEvenNumber.groupByKey

rddIsEvenNumbers: org.apache.spark.rdd.RDD[(String, Iterable[Int])] = ShuffledRDD[1] at groupByKey

Page 30: Spark Hands-on

rddVisits

combineByKey:

Spark Core

Shuffle

(February, (5, 1))

(January, (21, 5))

(June, (2,2))

(March, (2,2))

rddMeanVisitsByMonth

scala> val rddMeanVistisByMonth = rddVisits.combineByKey(

(visit: Int) => (visit, 1),

(comb: (Int, Int), visit) => (comb._1 + visit, comb._2 + 1),

(combAcc: (Int, Int), comb: (Int, Int)) => (combAcc._1 + comb._1, combAcc._2 +

comb._2))

rddMeanVistisByMonth: org.apache.spark.rdd.RDD[(String, (Int, Int))] = ShuffledRDD[2]

2

1

3

(March, 4)

(March, 4)

(January, 4)

(January, 4)

(January, 3)

(January, 5)

(June, 2)

(March, 3)

(February, 5)

(June, 1)

(January, 5)

1

1

1

1

1

1

1

2

1

1

2

1

1

2

3

3

3

3

Page 31: Spark Hands-on

Acciones:

Las acciones son los métodos de Spark que hacen que se ejecute todo el workflow asociado a una acción. Hasta el

momento no se ha ejecutado ninguna operación ni se han movido los datos de los repositorios distribuidos.

Hay que tener cuidado con algunas de estas operaciones porque pueden dar como resultado el traer todos los datos de

un repositorio Big Data a una sola máquina.

A continuación enumeramos algunas de las usadas.

Spark Core

Page 32: Spark Hands-on

numVisits

count

Cuenta el número de registros de un RDD

countByKey: Map[K, Long]

Spark Core

(January, (3, 5, 7))

(March, (3))

(February, (5))

(June, (1, 2))

(March, (4, 4))

(January, (4, 4))

rddVisitsByMonth

count

scala> val numVisits = rddVisitsByMonth.count

numVisits: Int

6

Page 33: Spark Hands-on

visits

collect

Recolecta todos los datos de un RDD en forma de lista

countByKey: Map[K, Long]

Spark Core

(January, (3, 5, 7))

(March, (3))

(February, (5))

(June, (1, 2))

(March, (4, 4))

(January, (4, 4))

rddVisitsByMonth

collect

scala> val visits = rddVisitsByMonth.collect

numVisits: Array[(Int, List[Int]]

[(January, (3, 5, 7)),(March, (3)),

(February, (5)),(June, (1, 2))

(March, (4, 4))(January, (4, 4))]

Page 34: Spark Hands-on

VisitsMap

countByKey

Devuelve los datos al Driver en forma de Map con un contador por clave

countByKey: Map[K, Long]

Spark Core

(January, (3, 5, 7))

(March, (3))

(February, (5))

(June, (1, 2))

(March, (4, 4))

(January, (4, 4))

rddVisitsByMonth

countByKey

scala> val visitsMap = rddVisitsByMonth.countByKey

visitsMap: scala.collection.Map[String,Long]

{(January, 2),(March, 1),(June, 1),

(February, 1)}

Page 35: Spark Hands-on

foreach

Recorre todo el RDD ejecutando una acción. Esta acción no debe devolver ningún valor.

Spark Core

(January, (3, 5, 7))

(March, (3))

(February, (5))

(June, (1, 2))

(March, (4, 4))

(January, (4, 4))

rddVisitsByMonth

scala> rddVisitsByMonth.foreach(tuple => println(tuple._2.reduce(_ + _)))

15

3

5

3

8

8

Page 36: Spark Hands-on

Variables compartidas:

Las variables compartidas son tipos de variables especiales que se pueden usar dentro de las tareas de Spark.

Aunque se crean en el Driver se actualizan y se les da uso en los Workers, dentro de cada tarea de Spark.

Se dividen en dos tipos:

● Contadores distribuidos: accumulator

● Variables distribuidas por el cluster: broadcast

Spark Core

Page 37: Spark Hands-on

Contadores distribuidos:

Spark Core

scala> val blankLines = sc.accumulator(0)

scala> val nonEmpty = file.flatMap(line => {if (line == "") blankLines += 1; line.split(" ")})

scala> ("Blank lines: " + blankLines.value)

res0: String = Blank lines: 0

scala> nonEmpty.collect

scala> ("Blank lines: " + blankLines.value)

res2: String = Blank lines: 2

rddFile

“Hi There”

“I’m fine”

“I’m great”

Hi

There

i’m

fine

I’m

great

flatMap

nonEmpty

Page 38: Spark Hands-on

Variables Compartidas

scala> val correctionFactor = sc.broadCast(0.35)

scala> val prizesCorrected = prizes.map(idValue => (idValue._1, idValue._2 * correctionFactor.value))

rddPrizes

(art1, 1)

(art2, 0.5)

(art21, 0.5)

(art25, 4)

(art23, 2)

(art52, 40)

mapValues

(art1, 0.35)

(art2, 0.175)

(art21, 0.175)

(art25, 1.4)

(art23, 0.7)

(art52, 14)

prizesCorrected

0.35

Variables distribuidas por el cluster:

Page 39: Spark Hands-on

Spark Sql

case class Movie(movieId : Integer, name : String, genre : String)

case class Tag(userId : Integer, movieId : Integer, tag : String, timestamp : Long)

case class Rating(userId : Integer, movieId : Integer, rating : Float, timestamp : Long)

/**

*

*/

scala> val ratingCounter = ratingRdd.map(rating => (rating.movieId, 1).reduceByKey(

(counter1, counter2)=> counter1 + counter2)

scala> val idMovieRatingRdd = movieRdd.map(movie => (movie.movieId,

movie.name)).join(ratingCounter)

scala> idMovieRatingRdd.map(idMovieRating => (idMovieRating._2._2, idMovieRating._2._1))

.sortByKey(false).map(counterName => (counterName._2, counterName._1)).collect.head

Page 40: Spark Hands-on

Spark Sql

case class Movie(movieId : Integer, name : String, genre : String)

case class Tag(userId : Integer, movieId : Integer, tag : String, timestamp : Long)

case class Rating(userId : Integer, movieId : Integer, rating : Float, timestamp : Long)

/**

* Saca la película más vista

*/

scala> val ratingCounter = ratingRdd.map(rating => (rating.movieId, 1).reduceByKey(

(counter1, counter2)=> counter1 + counter2)

scala> val idMovieRatingRdd = movieRdd.map(movie => (movie.movieId,

movie.name)).join(ratingCounter)

scala> idMovieRatingRdd.map(idMovieRating => (idMovieRating._2._2, idMovieRating._2._1))

.sortByKey(false).map(counterName => (counterName._2, counterName._1)).collect.head

Page 41: Spark Hands-on

Spark Sql

case class Movie(movieId : Integer, name : String, genre : String)

case class Tag(userId : Integer, movieId : Integer, tag : String, timestamp : Long)

case class Rating(userId : Integer, movieId : Integer, rating : Float, timestamp : Long)

/**

*

*/

scala> val aux1 = ratingRdd.map(rating => (rating.movieId, rating.rating).combineByKey(

(rating: Int) => (rating, 1),

(comb: (Int, Int), rating) => (comb._1 + rating, comb._2 + 1),

(combAcc: (Int, Int), comb: (Int, Int)) => (combAcc._1 + comb._1, combAcc._2 +

comb._2)).map(idRatingSum => (idRatingSum._1, idRatingSum._2._1/ idRatingSum._2._2))

.filter(avgId => avgId._2 > 10)

scala> val aux2 = aux1.join(moviesRdd.map(movie => (movie.idMovie, (movie.name, movie.gender))))

scala> aux2.map(idAvgNameGender => (idAvgNameGender._2._1, idAvgNameGender._2._2))

.sortByKey(false).map(avgId => (avgId._2, avgId._1)).collect.head

Page 42: Spark Hands-on

Spark Sql

case class Movie(movieId : Integer, name : String, genre : String)

case class Tag(userId : Integer, movieId : Integer, tag : String, timestamp : Long)

case class Rating(userId : Integer, movieId : Integer, rating : Float, timestamp : Long)

/**

* Saca el nombre y género de la película con mejor media

*/

scala> val aux1 = ratingRdd.map(rating => (rating.movieId, rating.rating).combineByKey(

(rating: Int) => (rating, 1),

(comb: (Int, Int), rating) => (comb._1 + rating, comb._2 + 1),

(combAcc: (Int, Int), comb: (Int, Int)) => (combAcc._1 + comb._1, combAcc._2 +

comb._2)).map(idRatingSum => (idRatingSum._1, idRatingSum._2._1/ idRatingSum._2._2))

.filter(avgId => avgId._2 > 10)

scala> val aux2 = aux1.join(moviesRdd.map(movie => (movie.idMovie, (movie.name, movie.gender))))

scala> aux2.map(idAvgNameGender => (idAvgNameGender._2._1, idAvgNameGender._2._2))

.sortByKey(false).map(avgId => (avgId._2, avgId._1)).collect.head

Page 43: Spark Hands-on

Spark Sql

Proyecto: FlightsDataset: AirlinesObjetivo: Rellenar los métodos de una DSL en Scala y que los tests pasen correctamente.

Repositorio: https://github.com/SparkCodemotion/Flights

Page 44: Spark Hands-on
Page 45: Spark Hands-on

[email protected] [email protected]

Page 46: Spark Hands-on

Spark Sql

Spark SQL nace en la versión 1.0 y quiere aunar y mejorar diferentes iniciativas de “SQL-on-Hadoop” ya

existentes.

• Ejecuta consultas SQL / HiveQL sobre RDD’s o datasources.

• Conecta herramientas de BI a Spark mediante JDBC vía “thrift server”

• Manejo con Python, Scala, Java, R

Page 47: Spark Hands-on

Spark Sql

Un DataFrame es una colección de Rows que contiene un esquema específico indícando el nombre de

las columnas y el tipo de dato que contiene cada una de ellas.

Conceptualmente es equivalente a una tabla en una base de datos relacional pero con una capa de

optimización que transforma lógica SQL en un plan “físico” basado en RDD’s para ser ejecutados en

Spark.

Page 48: Spark Hands-on

Spark Sql

El trabajo con SQL puede hacerse de forma directa haciendo consultas en este lenguaje o haciendo uso

de una completa API que han desarrollado y que permite trabajar de forma programática con todas la

funcionalidad del lenguaje y añadiendo la propia, integrada totalmente con el core de Spark.

• Proyección y filtrado de columnas• Joins entre datasources diferentes• Funciones de agregación• Soporte para UDF’s• API extensible

Page 49: Spark Hands-on

Spark Sql

Page 50: Spark Hands-on

Spark Streaming

Page 51: Spark Hands-on

Spark Sql

case class Movie(movieId : Integer, name : String, genre : String)

case class Tag(userId : Integer, movieId : Integer, tag : String, timestamp : Long)

case class Rating(userId : Integer, movieId : Integer, rating : Float, timestamp : Long)

import org.apache.spark.sql.functions._

import sqlContext.implicits._

val moviesDF = sc.textFile("/home/gmunoz/datasets/ml/movies.dat")

.map( line => line.split("::")).map(m => Movie(m(0).toInt,m(1),m(2))).toDF().cache()

val tagsDF = sc.textFile("/home/gmunoz/datasets/ml/tags.dat")

.map( line => line.split("::")).map(t =>

Tag(t(0).toInt,t(1).toInt,t(2),t(3).toLong)).toDF().cache()

val ratingsDF = sc.textFile("/home/gmunoz/datasets/ml/ratings.dat")

.map( line => line.split("::")).map(r =>

Rating(r(0).toInt,r(1).toInt,r(2).toFloat,r(3).toLong)).toDF().cache()

Page 52: Spark Hands-on

Spark Sql

case class Movie(movieId : Integer, name : String, genre : String)

case class Tag(userId : Integer, movieId : Integer, tag : String, timestamp : Long)

case class Rating(userId : Integer, movieId : Integer, rating : Float, timestamp : Long)

/**

*

*/

ratingsDF.select('movieId).groupBy('movieId).agg(count('movieId) as "count").sort('count.desc)

.join(moviesDF.select('name, 'movieId), moviesDF("movieId") === ratingsDF("movieId"),

joinType = "inner")

.select('name, 'count).show(1)

Page 53: Spark Hands-on

Spark Sql

case class Movie(movieId : Integer, name : String, genre : String)

case class Tag(userId : Integer, movieId : Integer, tag : String, timestamp : Long)

case class Rating(userId : Integer, movieId : Integer, rating : Float, timestamp : Long)

/**

* Saca el nombre de la película más votada

*/

ratingsDF.select('movieId).groupBy('movieId).agg(count('movieId) as "count").sort('count.desc)

.join(moviesDF.select('name, 'movieId), moviesDF("movieId") === ratingsDF("movieId"),

joinType = "inner")

.select('name, 'count).show(1)

Page 54: Spark Hands-on

Spark Sql

case class Movie(movieId : Integer, name : String, genre : String)

case class Tag(userId : Integer, movieId : Integer, tag : String, timestamp : Long)

case class Rating(userId : Integer, movieId : Integer, rating : Float, timestamp : Long)

/**

* Saca el nombre de la película más votada

*/

ratingsDF.select('movieId).groupBy('movieId).agg(count('movieId) as "count").sort('count.desc)

.join(moviesDF.select('name, 'movieId), moviesDF("movieId") === ratingsDF("movieId"),

joinType = "inner")

.select('name, 'count).show(1)

/**

*

*/

ratingsDF.select('movieId,'rating).groupBy('movieId).agg(avg('rating) as "avg", count('rating)

as "count")

.filter('count > 10)

.sort('avg.desc)

.join(moviesDF.select('name, 'movieId, 'genre), moviesDF("movieId") ===

ratingsDF("movieId"), joinType = "inner")

.select('name, 'genre, 'avg).show(2)

Page 55: Spark Hands-on

Spark Sql

case class Movie(movieId : Integer, name : String, genre : String)

case class Tag(userId : Integer, movieId : Integer, tag : String, timestamp : Long)

case class Rating(userId : Integer, movieId : Integer, rating : Float, timestamp : Long)

/**

* Saca el nombre de la película más votada

*/

ratingsDF.select('movieId).groupBy('movieId).agg(count('movieId) as "count").sort('count.desc)

.join(moviesDF.select('name, 'movieId), moviesDF("movieId") === ratingsDF("movieId"),

joinType = "inner")

.select('name, 'count).show(1)

/**

* Saca el nombre y género de la película con mejor media

*/

ratingsDF.select('movieId,'rating).groupBy('movieId).agg(avg('rating) as "avg", count('rating)

as "count")

.filter('count > 10)

.sort('avg.desc)

.join(moviesDF.select('name, 'movieId, 'genre), moviesDF("movieId") ===

ratingsDF("movieId"), joinType = "inner")

.select('name, 'genre, 'avg).show(2)

Page 56: Spark Hands-on
Page 57: Spark Hands-on

[email protected] [email protected]

Page 58: Spark Hands-on

Spark Streaming

Un DStream representa una entrada de datos en tiempo real en un intervalo de tiempo determinado.

• La entrada de datos es dividida en micro batches.

• Cada micro-batch es un RDD

• El Dstream es una secuencia de RDD’s

Page 59: Spark Hands-on

Spark Streaming

Page 60: Spark Hands-on

SPARK STREAMING OVERVIEW

Page 61: Spark Hands-on

Spark Streaming

La entrada de streams de datos se produce a través de los llamados InputDStream o Receiver

• Es común usar sistemas como Kafka, Kinesis o Apache Flume

• Existen también receivers básicos como sockets, stream de ficheros o actores de akka.

• Es importante usar entradas de datos con tolerancia a fallos y alto throughput.

Page 62: Spark Hands-on

• map(func),

• flatMap(func),

• filter(func),

• count()

• repartition(numPartitions)

• union(otherStream)

• reduce(func),

• countByValue(),

• reduceByKey(func, [numTasks])

• join(otherStream, [numTasks]),

• transform()

SPARK STREAMING OVERVIEW

Page 63: Spark Hands-on

• window(windowLength, slideInterval)

• countByWindow(windowLength, slideInterval)

• reduceByWindow(func, windowLength, slideInterval)

• reduceByKeyAndWindow(func, windowLength, slideInterval, [numTasks])

• countByValueAndWindow(windowLength, slideInterval, [numTasks])

SPARK STREAMING OVERVIEW

Page 64: Spark Hands-on

• print()

• foreachRDD(func)

• saveAsObjectFiles(prefix, [suffix])

• saveAsTextFiles(prefix, [suffix])

• saveAsHadoopFiles(prefix, [suffix])

SPARK STREAMING OVERVIEW

Page 65: Spark Hands-on

SPARK STREAMING OVERVIEW

TransformRDD ForeachRDD

def transform[U](transformFunc: (RDD[T]) ⇒ RDD[U]) : DStream[U]

def foreachRDD(foreachFunc: (RDD[T], Time) ⇒ Unit): Unit

• Mezclar batch con streaming• Usar DataFrames en Streaming• Machine Learning en Streaming• Reusar código existente de Batch

• Enviar datos a sistemas externos (ej. DB)• Usar datasources de Spark SQL

Page 66: Spark Hands-on

Spark Streaming

Hay operaciones especiales que mantienen estados y se actualizan en cada batch interval, son llamadas

stateful.

• Estas operaciones son UpdateStateByKey y ReduceByKeyAndWindow

• Estos estados se mantienen en memoria. Se pueden crear, actualizar y eliminar.

• Estas operaciones requieren de checkpointing para recuperación de errores.

El flujo normal de un stream es el siguiente

• Cada Batch interval se genera un Dstream

• A los datos contenidos en ese Dstream se le aplican transformaciones

• Se realiza una o varias acciones con estos datos.

Page 67: Spark Hands-on

Spark Streaming

UpdateStateByKey ReduceByKeyAndWindow

def updateStateByKey[S](updateFunc: (Seq[V], Option[S])

⇒ Option[S])def reduceByKeyAndWindow(reduceFunc: (V, V) ⇒ V,

windowDuration: Duration)

• Para cada clave K mantiene un Option[S]• Option a None elimina el estado.

• Es igual que un reduceByKey pero adicionalmente toma una ventana de tiempo.

Page 68: Spark Hands-on

Spark Streaming

Spark SQL Spark MLlib

Page 69: Spark Hands-on

Spark Sql

val sparkConf = new SparkConf().setAppName("TwitterPopularTags")

val ssc = new StreamingContext(sparkConf, Seconds(2))

val stream = TwitterUtils.createStream(ssc, None, filters)

val hashTags = stream.flatMap(status => status.getText.split(" ").filter(_.startsWith("#")))

val topCounts60 = hashTags.map((_, 1)).reduceByKeyAndWindow(_ + _, Seconds(60))

.map{case (topic, count) => (count, topic)}

.transform(_.sortByKey(false))

val topCounts10 = hashTags.map((_, 1)).reduceByKeyAndWindow(_ + _, Seconds(10))

.map{case (topic, count) => (count, topic)}

.transform(_.sortByKey(false))

// Print popular hashtags

topCounts60.foreachRDD(rdd => {

val topList = rdd.take(10)

println("\nPopular topics in last 60 seconds (%s total):".format(rdd.count()))

topList.foreach{case (count, tag) => println("%s (%s tweets)".format(tag, count))}

})

ssc.start()

ssc.awaitTermination()

Page 70: Spark Hands-on
Page 71: Spark Hands-on

[email protected] [email protected]

Page 72: Spark Hands-on

MlLib

MlLib es la librería de Machine Learning de Spark. Su objetivo es dar los mecanismos necesarios para

poder realizar diferentes algoritmias de Machine Learning aplicadas a grandes cantidades de datos.

Como todas las piezas del ecosistema de Spark, tiene como base los RDDs para la ejecución de estas

algoritmias.

MlLib “únicamente” nos proporciona, de una manera sencilla y eficiente, los métodos y las API

necesarias para poder ejecutarlos, pero estos algoritmos tienen que ser alimentados por modelos

matemáticos generados por el usuario.

Page 73: Spark Hands-on

MlLib

MlLib tiene implementados varios algoritmos de distinta índole para distintos problemas de Machine

Learning.

Dada la variedad de algoritmia relacionadas con el Machine Learning y su complejidad explicar cada

uno de estos algoritmos queda fuera de este taller. No obstante pasamos ahora a enumerar los

distintos algoritmos soportados por MlLib

Page 74: Spark Hands-on

MlLib

Classification and regression

linear models (SVMs, logistic regression, linear regression)

naive Bayes

decision trees

ensembles of trees (Random Forests and Gradient-Boosted Trees)

isotonic regression

Page 75: Spark Hands-on

MlLib

Dimensionality reduction

singular value decomposition (SVD)

principal component analysis (PCA)

Feature extraction and transformation

Frequent pattern mining

FP-growth

association rules

PrefixSpan

Page 76: Spark Hands-on

MlLib

Collaborative filtering

alternating least squares (ALS)

Clustering

k-means

Gaussian mixture

power iteration clustering (PIC)

latent Dirichlet allocation (LDA)

streaming k-means

Page 77: Spark Hands-on

MlLib

import org.apache.spark.mllib.recommendation.ALS

import org.apache.spark.mllib.recommendation.MatrixFactorizationModel

import org.apache.spark.mllib.recommendation.Rating

val data = sc.textFile("data/mllib/als/test.data")

val ratings = data.map(_.split(',') match { case Array(user, item, rate) =>

Rating(user.toInt, item.toInt, rate.toDouble)

})

val rank = 10

val numIterations = 10

val model = ALS.train(ratings, rank, numIterations, 0.01)

val usersProducts = ratings.map {

case Rating(user, product, rate) => (user, product)

}

val predictions = model.predict(usersProducts).map { case Rating(user, product, rate) =>

((user, product), rate)

}

val ratesAndPreds = ratings.map { case Rating(user, product, rate) =>

((user, product), rate)

}.join(predictions)

Page 78: Spark Hands-on

MlLib

import org.apache.spark.mllib.clustering.{KMeans, KMeansModel}

import org.apache.spark.mllib.linalg.Vectors

// Load and parse the data

val data = sc.textFile("data/mllib/kmeans_data.txt")

val parsedData = data.map(s => Vectors.dense(s.split(' ').map(_.toDouble))).cache()

// Cluster the data into two classes using KMeans

val numClusters = 2

val numIterations = 20

val clusters = KMeans.train(parsedData, numClusters, numIterations)

// Evaluate clustering by computing Within Set Sum of Squared Errors

val WSSSE = clusters.computeCost(parsedData)

println("Within Set Sum of Squared Errors = " + WSSSE)

// Save and load model

clusters.save(sc, "myModelPath")

val sameModel = KMeansModel.load(sc, "myModelPath")

Page 79: Spark Hands-on