67
Workshop Apache Flink Dr. Rubén Casado @ruben_casado #2. 20 de Mayo de 2016 [email protected]

Workshop Apache Flink Madrid

Embed Size (px)

Citation preview

Page 1: Workshop Apache Flink Madrid

Workshop Apache FlinkDr. Rubén Casado

@ruben_casado

#2. 20 de Mayo de 2016

[email protected]

Page 2: Workshop Apache Flink Madrid

Apache Flink

• Stack tecnológico desarrollado inicialmente como proyecto de I+D Stratosphere por grupos de investigación de Berlín. Apache Incubator en Abril 2014 y Apache Top Level en Diciembre 2014.

• Motor de procesamiento en memoria

• Procesamiento de streaming puro. Batch es un tipo concreto de Streaming.

• API similar a Spark.

• Soporte nativo de iteraciones.

• Híbrido mediante Arquitectura Kappa.

• Ecosistema creciendo.

Page 3: Workshop Apache Flink Madrid

Ejemplos

• Batch

• Stream

Page 4: Workshop Apache Flink Madrid

Librerías

Ingesta y almacenamiento

de datos

Motores de procesamiento

Gestores de aplicaciones

y recursos

Clasificación

YARN

Page 5: Workshop Apache Flink Madrid

Comparación con otras tecnologías

API low-level high-level high-level

Data Transfer batch batch pipelined & batch

Memory Management

disk-based JVM-managed Active managed

Iterationsfile system

cachedin-memory

cached streamed

Fault tolerance task level task level job level

Good at massive scale out data explorationheavy backend &

iterative jobs

Libraries many external built-in & externalevolving built-in &

external

Batch processing

Streaming “true” mini batches “true”

API low-level high-level high-level

Fault tolerance tuple-level ACKs RDD-based (lineage)coarse

checkpointing

State not built-in external internal

Exactly once at least once exactly once exactly once

Windowing not built-in restricted flexible

Latency low medium low

Throughput medium high high

Streaming processing

Page 6: Workshop Apache Flink Madrid

Tecnologías

Streaming Si Micro-batches Si Si

Gestión de estado No Si. Escribe a disco. Si. Escribe a disco. Si. BD embebida.

Semánticaat least once

exactly-once con Trident

exactly once exactly once at least once

Ventana deslizante

Sí en 1.0 Si. Por tiempoSi. Por tiempo y nº

eltosNo

Ventana no-deslizante

Sí en 1.0Si. Por tiempo (micro-batch)

Si. Por tiempo y nº eltos.

Si. Por tiempo

Latencia < segundos segundos < segundos < segundos

Rendimiento ¿Medio? Alto Alto Alto

LenguajesJava, Scala, Ruby,

Python, Javascript, Perl

Scala, Java, Python, R Java, Scala, Python Java, Scala

Madurez ¿Alta? Media Baja Baja

Page 7: Workshop Apache Flink Madrid

1. Instalar Java 1.8

sudo add-apt-repository ppa:openjdk-r/ppa

sudo apt-get update

sudo apt-get install openjdk-8-jdk

Editar etc/environment para añadir la variable JAVA_HOME

JAVA_HOME=“/usr/lib/jvm/java-8-openjdk-XXX”

2. Instalar Scala 2.11

sudo apt-get remove scala-library scala

sudo wget www.scala-lang.org/files/archive/scala-2.11.8.deb

sudo dpkg -i scala-2.11.8.deb

[Si da errores] sudo apt-get install libjansi-java

[Si da errores] sudo apt-get -f install

sudo apt-get update

sudo apt-get install scala

3. Instalar mavensudo apt-get install maven

4. Descargar y descomprimir Flink 1.0.2

wget http://apache.rediris.es/flink/flink-1.0.2/flink-1.0.2-bin-hadoop27-scala_2.11.tgz

tar -zxvf flink-1.0.2-bin-hadoop27-scala_2.11.tgz

5. Probar Scala-Flink interactivo

bin/start-scala-shell.sh local

Preparación del entorno (1/2)

Page 8: Workshop Apache Flink Madrid

6. Crear un esqueleto maven

mvn archetype:generate \

-DarchetypeGroupId=org.apache.flink \

-DarchetypeArtifactId=flink-quickstart-java \

-DarchetypeVersion=1.0.0 \

-DgroupId=org.apache.flink.quickstart \

-DartifactId=flink-java-project \

-Dversion=0.1 \

-Dpackage=org.apache.flink.quickstart \

-DinteractiveMode=false

cd flink-java-project

mvn clean install

mvn clean package

7. Instalar IDE. Importar proyecto en el IDE

[Intelli J] Import project → Import project from external model [existing sources]→ Maven

8. Ejecutar WordCount para validar instalación y abrir localhost:8081 para ver la app de admin

9. Desplegar en cluster

mvn clean package → en /target obtenemos el .jar

flink-1.0.1/bin/start-local.sh → arrancar cluster local, existen otras opciones

[opcional] flink-1.0.1/ tail log flink-*-jobmanager* → ver si todo está OK

flink-1.0.1/bin/flink run –c MainClassName ../target/flink-java-project-0.1.jar → lanzar job

Preparación del entorno (2/2)

mvn archetype:generate \

-DarchetypeGroupId=org.apache.flink \

-DarchetypeArtifactId=flink-quickstart-java \

-DarchetypeVersion=1.0.0 \

-DgroupId=org.apache.flink.quickstart \

-DartifactId=flink-java-project \

-Dversion=0.1 \

-Dpackage=org.apache.flink.quickstart \

-DinteractiveMode=false

http://dataartisans.github.io/flink-training/devSetup/handsOn.html

Page 9: Workshop Apache Flink Madrid

• Client• Master (Job Manager)• Worker (Task Manager)

Arquitectura

Client

Job Manager

Task Manager

Task Manager

Task Manager

Page 10: Workshop Apache Flink Madrid

• Local. Similar al Driver de Spark• Construye el grafo de transformaciones (DAF) y lo

optimiza• Pasa el grafo al Job Manager • Recoge los resultados

Job Manager

Client

case class Path (from: Long, to: Long)val tc = edges.iterate(10) {

paths: DataSet[Path] =>val next = paths

.join(edges)

.where("to")

.equalTo("from") {(path, edge) =>

Path(path.from, edge.to)}.union(paths).distinct()

next} Optimizer

Type extraction

Data Sourceorders.tbl

Filter

Map DataSourcelineitem.tbl

JoinHybrid Hash

buildHT probe

hash-part [0] hash-part [0]

GroupRed

sort

forward

Client

Page 11: Workshop Apache Flink Madrid

• Paralelizacion: Crea el grafo de ejecución• Scheduling: Asigna las tasks a los task managers• State: Supervisa la ejecución

Job Manager

Job Manager

Data

Sourceorders.tbl

Filter

MapDataSour

celineitem.tbl

JoinHybrid Hash

build

HT

prob

e

hash-part [0] hash-part [0]

GroupRed

sort

forwar

d

Task Manager

Task Manager

Task Manager

Task Manager

Data

Sourceorders.tbl

Filter

MapDataSour

celineitem.tbl

JoinHybrid Hash

build

HT

prob

e

hash-part [0] hash-part [0]

GroupRed

sort

forwar

d

Data

Sourceorders.tbl

Filter

MapDataSour

celineitem.tbl

JoinHybrid Hash

build

HT

prob

e

hash-part [0] hash-part [0]

GroupRed

sort

forwar

d

Data

Sourceorders.tbl

Filter

MapDataSour

celineitem.tbl

JoinHybrid Hash

build

HT

prob

e

hash-part [0] hash-part [0]

GroupRed

sort

forwar

d

Data

Sourceorders.tbl

Filter

MapDataSour

celineitem.tbl

JoinHybrid Hash

build

HT

prob

e

hash-part [0] hash-part [0]

GroupRed

sort

forwar

d

Page 12: Workshop Apache Flink Madrid

• Las operaciones se dividen en tasks según el grado de paralelismo definido

• Cada instancia paralela de una operación ejecuta la operación en un task slot separado

• El scheduler puede ejecutar diversas tasks de diferentes operaciones en el mismo task slot

Task Manager

Slot

Task ManagerTask Manager

Slot

Slot

Task Manager

Page 13: Workshop Apache Flink Madrid

13

Gelly

Table

ML

SA

MO

A

DataSet (Java/Scala/Python) DataStream (Java/Scala)

Hadoop

M/R

Local Remote Yarn Tez Embedded

Data

flow

Da

taflo

w (

WiP

)

MR

QL

Table

Ca

sca

din

g (

WiP

)

Streaming dataflow runtime

DataSet

Page 14: Workshop Apache Flink Madrid

• Lista distribuida de elementos en memoria similar a RDD de Spark

• Los elementos pueden ser simples (String, Long, Integer, Boolean) o compuestos

(Array, Tuple, Pojo)

• Se crea a partir de un ExecutionEnviorment o tras aplicar transformaciones a otro

DataSet

• Existen diferentes subclases de DataSet con sus peculiaridades

• Data Source → Orígenes de datos desde lo que un ExecutionEnviorment puede

generar un Dataset (p.e. fichero)

• Data Sink → Destino de datos donde se puede volcar un DataSet (p.e. fichero)

DataSet

Page 15: Workshop Apache Flink Madrid

Data Source DataSet Data Sink

DataSet

• API proporcionada por el ExecutionEnviorment

• Genera objetos DataSeta partir de una fuente de datos (fichero, base de datos, etc.)

• Se puede añadir Data Source nuevos

• Estructura de datos básica en Flink para batch processing

• Proporciona el API para aplicar transformaciones sobre un DataSet y generar nuevos DataSets(o clases derivadas)

• API proporcionada por la clase DataSet

• Permite exportar el contenido de un DataSethacia otro sistema (fichero, base de datos, etc.)

• Se puede añadir Data Sinks nuevos

Page 16: Workshop Apache Flink Madrid

object WordCount {

def main(args: Array[String]) {

// Crear el ExecutionEnvironment

val env = ExecutionEnvironment.getExecutionEnvironment

// Crear un Dataset con un DataSource

val text = env.fromElements("hola", "qué tal", "Apache Flink")

// Transformaciones sobre un DataSet

val counts = text.flatMap { _.toLowerCase.split(“ ") }

.map { (_, 1) }

.groupBy(0)

.sum(1)

// Usar un DataSink para conseguir resultados

counts.print()

}

}

DataSet

Page 17: Workshop Apache Flink Madrid

DataSet API

DataSet: yDataSet: x

val x = env.fromElements(“b”, “a”, “c”)

val y = x.map( e =>(e,1))

x.print()

y.print()

Devuelve un nuevo DataSet aplicando una función a cada uno de los elementos del DataSet original

Page 18: Workshop Apache Flink Madrid

DataSet API

DataSet: yDataSet: x

val x = env.fromElements(1, 2, 3)

val y = x.filter( e => e%2==1)

x.print()

y.print()

Devuelve un nuevo DataSet que solo incluye los elementos que cumplen la condición

Page 19: Workshop Apache Flink Madrid

DataSet API

DataSet: yDataSet: x

Devuelve un nuevo DataSet aplicando una función a cada uno de los elementos del DataSet original y después apilando los resultados.

val x = env.fromElements(1, 2, 3)

val y = x.flatMap( e => Array (e, e*100, 42))

x.print()

y.print()

Page 20: Workshop Apache Flink Madrid

x = sc.parallelize([1,2,3,4])

y = x.collect()

DataSet API

DataSet: x

val x = env.fromElements(1, 2, 0)

x.count()

Devuelve un Long con el nº de elementos del DataSet

3

COUNT

Page 21: Workshop Apache Flink Madrid

x = sc.parallelize([1,2,3,4])

y = x.collect()

DataSet API

DataSet: x

val x = env.fromElements(1, 2, 0)

x.print()

Imprime por la salida estándar (System.out) los elementos del DataSet

120

PRINT

Page 22: Workshop Apache Flink Madrid

• ¿En cuántas líneas del fichero LICENSE aparece la palabra “contributor”?

• Tips

• val mydataset = env.readTextFile(“LICENSE”)

• Función string.contains(string2)de Scala

• Si se quiere tener en cuenta apariciones tanto en minúscula como en mayúscula: string.toLowerCase()

Ejercicio 1 DataSet API

Page 23: Workshop Apache Flink Madrid

Tipos de Datos para DataSet

• Tipos básicos de Java– String, Long, Integer, Boolean,…

– Arrays

• Tipos compuestos– Tuples

– Pojo

– Scala Case class

• No todos los tipos pueden ser usados como claves– Tienen que ser comparables

23

Page 24: Workshop Apache Flink Madrid

Tuples

• La manera más fácil y eficiente de encapsular datos en Flink

• Tuple1 hasta Tuple25

Tuple2<String, String> person = new Tuple2<String, String>("Max", "Mustermann”);

Tuple3<String, String, Integer> person =

new Tuple3<String, String, Integer>("Max", "Mustermann", 42);

Tuple4<String, String, Integer, Boolean> person =

new Tuple4<String, String, Integer, Boolean>("Max", "Mustermann", 42, true);

// el primer campo es el 0

String firstName = person.f0;

String secondName = person.f1;

Integer age = person.f2;

Boolean fired = person.f3;

24

Page 25: Workshop Apache Flink Madrid

Pojo

• Cualquier clase Java que– Tenga un constructor vacío por defecto

– Todos sus campos son accesibles (public o getter/setter)

public class Person {

public int id;

public String name;

public Person() {};

public Person(int id, String name) {…};

}

DataSet<Person> d = env.fromElements(new Person(1, ”Ruben”));

• Permite definir claves por nombreDataSet<Person> p = …

// agrupar por el campo “name”

d.groupBy(“name”).groupReduce(…);

25

Page 26: Workshop Apache Flink Madrid

Scala Case Classes

• Soporte nativo para case classes de Scala

case class Person(id: Int, name: String)

d: DataSet[Person] = env.fromElements(new Person(1, “Ruben”)

• Permite definer claves por nombre

// agrupar por el campo “name”

d.groupBy(“name”).groupReduce(…)

26

Page 27: Workshop Apache Flink Madrid

DataSet: x

val x = env.fromElements((1,5), (2,5), (1, 4))

val y =x.groupBy(0)

x.print()

y.sum(1).print()

GroupedDataSet: y

(1,5), (2,5), (1, 4)

(1,9), (2,5)

Devuelve un nuevo GroupedDataSet agrupando los elementos por la clave especificada. La clave puede ser un campo de un Tuple/Pojo/Case o una función que genere la clave.

DataSet API

Page 28: Workshop Apache Flink Madrid

DataSet APIGroupedDataset / DataSet: x DataSet: y

Devuelve un DataSet de un único elemento combinando todos los elementos del DataSet original mediante una función asociativa. Se puede aplicar en GroupedDataset, generando en este caso un DataSet con un elemento por cada clave.

val x = env.fromElements(1,2,3,4)

val y =x.reduce(_ + _)

x.print()

y.print()

Page 29: Workshop Apache Flink Madrid

DataSet APIGroupedDataset / DataSet: x DataSet: y

val x = env.fromElements((“hola”,1), (“adiós”, 1), (“hola”, 3))

val y =x.groupBy(0).reduceGroup(elements => elements.length)

x.print()

y.print()

REDUCEGROUP

Devuelve un DataSet de un único elemento combinando todos los elementos del DataSet original mediante una función que recibe todos elementos en forma de iterable. Se puede aplicar en GroupedDataset, generando en este caso un DataSet con un elemento por cada clave.

12

((“hola”,1), (“adiós”, 1), (“hola”, 3)

Page 30: Workshop Apache Flink Madrid

• Ejecutar y analizar el código el ejemplo de WordCount desde el IDE

• Seguir los pasos de la slide “Preparar Entorno (2/2)”

• Ejecutar el Main del archivo WordCount.java desde el IDE

• Analizar clase LineSplitter Lógica concreta de un FlatMap

• ¿Cómo implementarías (sin usar la función SUM) la cuenta de palabras? Lógica concreta de un ReduceGroupe

Ejercicio 2 DataSet API

Page 31: Workshop Apache Flink Madrid

WordCount: FlatMap

public static class LineSplitter

implements FlatMapFunction<String, Tuple2<String, Integer>> {

@Override

public void flatMap(String value, Collector<Tuple2<String, Integer>> out){

// normalizer y partir la linea por palabras

String[] tokens = value.toLowerCase().split("\\W+");

// emitir un par (palabra, 1) por cada palabra

for (String token : tokens) {

if (token.length() > 0) {

out.collect(new Tuple2<String, Integer>(token, 1));

}

}

}

}

Page 32: Workshop Apache Flink Madrid

WordCount: FlatMap: Interface

public static class LineSplitter

implements FlatMapFunction<String, Tuple2<String, Integer>> {

@Override

public void flatMap(String value, Collector<Tuple2<String, Integer>> out){

// normalizer y partir la linea por palabras

String[] tokens = value.toLowerCase().split("\\W+");

// emitir un par (palabra, 1) por cada palabra

for (String token : tokens) {

if (token.length() > 0) {

out.collect(new Tuple2<String, Integer>(token, 1));

}

}

}

}

32

Page 33: Workshop Apache Flink Madrid

WordCount: FlatMap: tipos

public static class LineSplitter

implements FlatMapFunction<String, Tuple2<String, Integer>> {

@Override

public void flatMap(String value, Collector<Tuple2<String, Integer>> out){

// normalizar y partir la linea por palabras

String[] tokens = value.toLowerCase().split("\\W+");

// emitir un par (palabra, 1) por cada palabra

for (String token : tokens) {

if (token.length() > 0) {

out.collect(new Tuple2<String, Integer>(token, 1));

}

}

}

}

33

Page 34: Workshop Apache Flink Madrid

WordCount: FlatMap: collector

public static class LineSplitter

implements FlatMapFunction<String, Tuple2<String, Integer>> {

@Override

public void flatMap(String value, Collector<Tuple2<String, Integer>> out){

// normalizer y partir la linea por palabras

String[] tokens = value.toLowerCase().split("\\W+");

// emitir un par (palabra, 1) por cada palabra

for (String token : tokens) {

if (token.length() > 0) {

out.collect(new Tuple2<String, Integer>(token, 1));

}

}

}

}

Page 35: Workshop Apache Flink Madrid

WordCount: GroupReduce

public static class SumWords implements

GroupReduceFunction<Tuple2<String, Integer>, Tuple2<String, Integer>> {

@Override

public void reduce(Iterable<Tuple2<String, Integer>> values,

Collector<Tuple2<String, Integer>> out) {

int count = 0;

String word = null;

for (Tuple2<String, Integer> tuple : values) {

word = tuple.f0;

count++;

}

out.collect(new Tuple2<String, Integer>(word, count));

}

}

Page 36: Workshop Apache Flink Madrid

WordCount: GroupReduce: Interface

public static class SumWords implements

GroupReduceFunction<Tuple2<String, Integer>, Tuple2<String, Integer>> {

@Override

public void reduce(Iterable<Tuple2<String, Integer>> values,

Collector<Tuple2<String, Integer>> out) {

int count = 0;

String word = null;

for (Tuple2<String, Integer> tuple : values) {

word = tuple.f0;

count++;

}

out.collect(new Tuple2<String, Integer>(word, count));

}

}

Page 37: Workshop Apache Flink Madrid

WordCount: GroupReduce: tipos

public static class SumWords implements

GroupReduceFunction<Tuple2<String, Integer>, Tuple2<String, Integer>> {

@Override

public void reduce(Iterable<Tuple2<String, Integer>> values,

Collector<Tuple2<String, Integer>> out) {

int count = 0;

String word = null;

for (Tuple2<String, Integer> tuple : values) {

word = tuple.f0;

count++;

}

out.collect(new Tuple2<String, Integer>(word, count));

}

}

Page 38: Workshop Apache Flink Madrid

WordCount: GroupReduce: collector

public static class SumWords implements

GroupReduceFunction<Tuple2<String, Integer>, Tuple2<String, Integer>> {

@Override

public void reduce(Iterable<Tuple2<String, Integer>> values,

Collector<Tuple2<String, Integer>> out) {

int count = 0;

String word = null;

for (Tuple2<String, Integer> tuple : values) {

word = tuple.f0;

count++;

}

out.collect(new Tuple2<String, Integer>(word, count));

}

}

Page 39: Workshop Apache Flink Madrid

Desde Fichero

• readTextFile(path, [TextInputFormat]): Lee línea a línea y las devuelve como

String

• readCsvFile(path, [CsvInputFormat ]):Lee línea a línea ficheros con campos

separados por comas (u otro char). Genera un DataSet de tuplas o objetos case classes.

• readHadoopFile(FileInputFormat, Key, Value, path

,[FileInputFormat ]) : Crea un JobConf y lee el fichero del path especificado

usando el FileInputFormat. Se devuelven como Tuple2<Key, Value>

Data Sources para DataSet

Page 40: Workshop Apache Flink Madrid

Desde Colecciones

• fromCollection(Seq): Crear un DataSet a partir de un objeto Seq. Todos los elementos

de la colección tienen que ser del mismo tipo.

• fromCollection(Iterator): Crear un DataSet a partir de un objeto Iterator. El tipo

de dato es el devuelto por el iterador.

• fromElements(elements: _*): Crea un DataSet a partir de la secuencia de

elementos introducidos directamente.

Genéricos

• readFile(inputFormat, path): Lee desde fichero pero con un format genérico que

se especifica.

• createInput(inputFormat) : Para crear un nuevo data Source (por ejemplo

Kafka).

Data Sources para DataSet

Page 41: Workshop Apache Flink Madrid

ExecutionEnvironment env = ExecutionEnvironment.getExecutionEnvironment();

// Leer desde fichero local o Sistema de ficheros distribuido

DataSet<String> localLines = env.readTextFile(”/path/to/my/textfile");

// leer un CSV con 3 campos

DataSet<Tuple3<Integer, String, Double>> csvInput =

env.readCsvFile(“/the/CSV/file")

.types(Integer.class, String.class, Double.class);

// leer un CSV de 5 campos pero se queda solo con el primero y el cuarto

DataSet<Tuple2<String, Double>> csvInput = env.readCsvFile(“/the/CSV/file")

.ignoreFirstLine()

.includeFields("10010")

.types(String.class, Double.class);

// leer un CSV y parsearlo como una clase POJO

DataSet<Film> films = env.readCsvFile(“the/CSV/file“)

.pojoType(

Film.class,

"name",

"year",

"nominations",

"genre1");

Data Sources: ficheros

Page 42: Workshop Apache Flink Madrid

ExecutionEnvironment env = ExecutionEnvironment.getExecutionEnvironment();

// leer de elementos introducidos directamente

DataSet<String> names = env.fromElements(“Some”, “Example”, “Strings”);

// leer desde una colección

List<String> list = new ArrayList<String>();

list.add(“Some”);

list.add(“Example”);

list.add(“Strings”);

DataSet<String> names = env.fromCollection(list);

Data Sources: colecciones

Page 43: Workshop Apache Flink Madrid

Text• writeAsText(“/path/to/file”)

• writeAsCSV(“/path/to/file”, “;”)

• output(outputFormat)

CSV• writeAsCsv(“/path/to/file”)

Devolver resultados al cliente• print()

• collect()

• count()

Data Sinks para DataSet

Page 44: Workshop Apache Flink Madrid

// Reduce → Recibe 2 parámetros para aplicar de forma asociativa

val text:DataSet[Tuple2[String, Int]] = env.fromElements(Tuple2("uno",1),Tuple2 ("dos",2),Tuple2 ("uno",11))

text.groupBy(0).reduce( (x, y) => (x._1, x._2 + y._2)).print()

// ReduceGroup -> Recibe iterador como parámetro

val text:DataSet[Tuple2[String, Int]] = env.fromElements(Tuple2("uno",1),Tuple2 ("dos",2),Tuple2 ("uno",11))

text.groupBy(0).reduceGroup(x => x.length).print()

// Pasar funciones a las transformaciones

val numeros:DataSet[Int] =

env.fromElements(1,2,4,6,20)

numeros.map(new MiMap).print()

numeros.reduce(new MiReduce).print()

class MiMap extends MapFunction[Int, Int] {

def map(n: Int): Int = {

return n*2

}

}

class MiReduce extends ReduceFunction[Int] {

def reduce(a: Int, b:Int): Int = {

return a+b

}}

// Parsear un Dataset con una case class

case class Persona (id: Int, nombre: String)

val d: DataSet[Persona] = env.fromElements(new Persona(1, “Rubén”)

// usar un campo como clave

d.groupBy(“nombre”).groupReduce(…)

DataSet API en Scala

Page 45: Workshop Apache Flink Madrid

Transformación Descripción

MapDado un elemento, genera otro elemento

data.map { x => x.toInt }

FlatMapDado un elemento produce 0, 1 o más elementos

data.flatMap { str => str.split(" ") }

MapPartition

Recibe un iterador y produce un nº arbitrario de resultados. Se ejecuta por cada partición.

data.mapPartition { in => in map { (_, 1) } }

Filter

Recibe un elemento y lo devuelve si la evaluación de la función es True sobre ese elemento

data.filter { _ > 1000 }

ReduceCombina elementos en uno único mediante una función asociativa. Se puede aplicar en GroupedDatasets

data.reduce { _ + _ }

ReduceGroupReduce grupos de elementos en uno o varios elementos.

data.reduceGroup { elements => elements.sum }

Aggregate

Agrega grupos de elementos en uno único. Se puede aplicar en DataSets y GroupedDasets

val input: DataSet[(Int, String, Double)] = // [...]

val output: DataSet[(Int, String, Doublr)] =

input.aggregate(SUM, 0).aggregate(MIN, 2);

Hay atajos para algunas funciones de agregación habituales

val input: DataSet[(Int, String, Double)] = // [...] val output:

DataSet[(Int, String, Doublr)] = input.sum(0).min(2)

Transformaciones para DataSet

Page 46: Workshop Apache Flink Madrid

Transformación Descripción

Distinct Devuelve los elementos distintos de un DataSet

data.distinct()

Join Une dos datasets creando todos los pares de elementos que son iguales en sus claves. Hay otras opciones de join con Join Hints

// Los elementos son tuplas y se usa el campo 0 del Dataset 1 con el 1 del DataSet 2

val result = input1.join(input2).where(0).equalTo(1)

OuterJoin Ejecutar left, right and full outer joins

keys.val joined = left.leftOuterJoin(right).where(0).equalTo(1)

{ (left, right) => val a = if (left == null) "none" else left._1 (a, right) }

Union Produce la union de dos DataSets.

data.union(data2)

Cross Producto cartestiano entre dos DataSets creando todos los pares de elementos.

val data1: DataSet[Int] = // [...]

val data2: DataSet[String] = // [...]

val result: DataSet[(Int, String)] = data1.cross(data2)

CoGroup Versión de 2 dimensiones del Reduce. Agrupa el input de uno o más campos y luego une los grupos. La función de transformación se aplica a los pares de grupos

data1.coGroup(data2).where(0).equalTo(1).with( cogroupfunction)

First-n Devuelve N elementos del DataSet.

data1.first(3)

Sort Partition Ordena una partición.val in: DataSet[(Int, String)] = // [...] val result = in.sortPartition(1,

Order.ASCENDING).mapPartition { ... }

Transformaciones para DataSet

Page 47: Workshop Apache Flink Madrid

• Usar el fichero “pictures.csv”

https://cs.uwaterloo.ca/~s255khan/files/pictures.csv

• Modelar cada película con una Case class / Pojo/ Tuple

• Calcular con el API de DataSet

• Media de nominaciones de las películas

• Media en Metacritic, agrupado por géneros, de las películas

• Duración media de las películas ganadoras por décadas

• ¿Cuántas películas ganadoras incluyen al menos una de las palabras de su título en la sinopsis?

• ¿Cuántas películas ganadoras incluyen todas las palabras de su título en la sinopsis?

• ¿Cuál es la desviación estándar del rating de las películas ganadoras en el siglo XXI?

name year nominations rating duration genre1 genre2 release metacritic synopsis

Birdman 2014 9 7.8 119 Comedy Drama November 88Illustrated upon the progress of his latest Broadway play a former popular actors struggle tocope with his current life as a wasted actor is shown.

12 Years a Slave 2013 9 8.1 134 Biography Drama November 97In the antebellum United States Solomon Northup a free black man from upstate New York isabducted and sold into slavery.

Ejercicio 3 DataSet API

Page 48: Workshop Apache Flink Madrid

48

Gelly

Table

ML

SA

MO

A

DataSet (Java/Scala/Python) DataStream (Java/Scala)

Hadoop

M/R

Local Remote Yarn Tez Embedded

Data

flow

Da

taflo

w (

WiP

)

MR

QL

Table

Ca

sca

din

g (

WiP

)

Streaming dataflow runtime

DataStream

Page 49: Workshop Apache Flink Madrid

Arquitectura de un sistema de streaming processing

Capa de adquisición

Cola de mensajes

Capa de procesamiento

Almacenamiento en memoria

Capa de acceso

Almacenamiento larga duración

Origen

Page 50: Workshop Apache Flink Madrid

Capa de procesamiento: semántica

At most once: cada mensaje se procesa como máximo una vez. Seasegura que ningún mensaje es procesado más de una vez, pero podríapasar que algún mensaje no se procesase.

La más sencilla, no se requiere implementar ninguna lógica.

At least once: cada mensaje se procesa al menos una vez. Se aseguraque todos los mensajes recibidos son procesados, pero podría pasarque algún mensaje se procesase más de una vez.

• El sistema tiene que mantener un registro de los mensajes que se envió ala capa de procesamiento y enviar un ACK de recibimiento.

Exactly once: cada mensaje se procesa exactamente una vez. Ningúnmensaje se queda sin procesar y ningún mensaje se procesa más deuna vez.

• La más compleja. El sistema debe mantener un registro de los mensajesenviados a la capa de procesamiento pero también detectar losduplicados.

Page 51: Workshop Apache Flink Madrid

Para un tiempo tn concreto, ¿depende la salida del sistema solo de lainformación recibida en tn (stateless) o también de la recibida en tn-1

(statefull)?

Ejemplos:

• Lanzar una alarma cuando el PM10 sobrepase el valor de 25

• Identificar los trending topics en Twitter

• Contar el nº de páginas vistas por hora por cada usuario

Los frameworks para streaming processing suelen disponer de APIs paragestionar estados Flink lo tiene automático y manual

Gestión del estadoEjemplo statefull

Capa de procesamiento: estado

Page 52: Workshop Apache Flink Madrid

Noción del tiempo

• Event time: tiempo en el que el dato se generó

• Stream/Ingestion time (system timestmap): tiempo en el que eldato entró en el sistema

• Skew: diferencia entre el event time y el stream time

Capa de procesamiento: eventos

Page 53: Workshop Apache Flink Madrid

Ventana de datos (window): porción finita del streaming de datossobre la que poder ejecutar los algoritmos.

• Lo habitual es por tiempo, aunque podría ser por nº de elementos u otrosmecanismos de disparo.

• Existen diferentes tipos de ventanas: deslizante (sliding) y no deslizantes(tumbling)

Capa de procesamiento: ventanas

Page 54: Workshop Apache Flink Madrid

Ventana deslizante

Sliding Window: técnica para el procesamiento de datos en continuoque divide el flujo en grupos finitos basándose en dos parámetros.

• Longitud de la ventana (window length): Tiempo de datos que se tendráen cuenta en el cálculo (desde tactual hasta tactual – longitud_ventana)

• Intervalo: cada cuánto se recomputa el cálculo sobre los datos de laventana

Ejemplo: Actualizar cada 1 segundo (intervalo) el valor de la mayor compra delos últimos 2 segundos (longitud de la ventana)

Page 55: Workshop Apache Flink Madrid

Ventana no deslizante

Tumbling window: técnica para el procesamiento de datos en continuoque divide el flujo en grupos finitos basándose solamente en lalongitud de la ventana.

• La longitud de la ventana puede ser por tiempo. Equivalente a ventanadeslizante donde longitud_ventana = intervalo

• La longitud de la ventana puede ser por nº de elementos. Hasta que no sereciba ese nº de elementos fijado no se produce ningún resultado.

Page 56: Workshop Apache Flink Madrid

DataStream

• Lista distribuida de infinitos elementos NO micro-batch

• Se crea a partir de un StreamExecutionEnvironment o tras aplicar transformaciones a otro DataStream

• Mismos conceptos de DataSource y Data Sinks

• Las funciones de agregación solo tienen sentido sobre ventanas

• Las funciones sobre Windows cuyo stream no es Clave-Valor (KeyedDataStream) NO son paralelas

• Conceptos de ventanas (Tamaño y Trigger)

Tumbling time window

.timeWindow(Time.minutes(1))

Sliding time window

.timeWindow(Time.minutes(1), Time.seconds(30))

Tumbling count window

.countWindow(100)

Sliding count window

.countWindow(100, 10)

Trigger

.trigger(new miDisparador())

Page 57: Workshop Apache Flink Madrid

DataStream

Heredan

Generan

Page 58: Workshop Apache Flink Madrid

DataStream

StreamExecutionEnvironment env =

StreamExecutionEnvironment.getExecutionEnvironment();

String url = "wss://stream.meetup.com/2/rsvps";

DataStream<MeetupRSVGevent> events = env.addSource(new

MeetupStreamingSource(url));

events.filter(new FilterNullsEvents())

.keyBy("venue")

.timeWindow(Time.seconds(5))

.apply(new PojoCountPeople()).print();

env.execute("Meetup Madrid DataStream");

Page 59: Workshop Apache Flink Madrid

Data Sources para DataStream

Desde fichero

• readTextFile(path)

• readFile(path)

• readFileStream ()

Desde Socket

• socketTextStream

Desde Colección

• fromCollection(Seq)

• fromCollection(Iterator)

• fromElements(elements: _*)

Genérico

• addSource () Para Kafka addSource(new FlinkKafkaConsumer09<>)

Page 60: Workshop Apache Flink Madrid

Data Sinks para DataStreams

A fichero

• writeAsText()

• writeAsCsv(...)

• writeUsingOutputFormat()

Imprimir

• print()

• printToErr()

A Socket

• writeToSocket

Genérico

• addSink para volcar a Kafka addSink(new FlinkKafkaConsumer09[](…)

Page 61: Workshop Apache Flink Madrid

Transformación Descripción

MapDataStream → DataStream

Dado un element genera otrodataStream.map { x => x * 2 }

FlatMapDataStream → DataStream

Dado un element genera 0,1 o más elementosdataStream.flatMap { str => str.split(" ") }

FilterDataStream → DataStream

Evalua una función boleana sobre el element y lo devuelve si es TruedataStream.filter { _ != 0 }

KeyByDataStream → KeyedStream

Particionado por clave para ejecutar operaciones en paralelodataStream.keyBy("someKey")

dataStream.keyBy(0)

ReduceKeyedStream → DataStream

Aplica la función asociativa con el anterior resultado y el nuevo elemento

keyedStream.reduce { _ + _ }

FoldKeyedStream → DataStream

Combina el resultado anterior con el Nuevo element, utilizando un valor inicial

val result: DataStream[String] = keyedStream.fold("start",

(str, i) => { str + "-" + i })

Transformaciones para DataStream

Page 62: Workshop Apache Flink Madrid

Transformación Descripción

AggregationsKeyedStream → DataStream

Agregaciones. Min devuelve el mínimo valor y MinBy el elemento que contiene el mínimo valorkeyedStream.sum(0) keyedStream.sum("key")

keyedStream.min(0) keyedStream.min("key")

keyedStream.max(0) keyedStream.max("key")

keyedStream.minBy(0) keyedStream.minBy("key")

keyedStream.maxBy(0) keyedStream.maxBy("key")

WindowKeyedStream → WindowedStream

Agrupa los datos (en KeyedStream) según la definición de la ventana.

dataStream.keyBy(0).window(TumblingEventTimeWindows.of(Ti

me.seconds(5)))

WindowAllDataStream → AllWindowedStream

Lo mismo pero sobre DataStream (no KeyedStream). Puede no ser paralelodataStream.windowAll(TumblingEventTimeWindows.of(Time.sec

onds(5)))

ApplyWindowedStream → DataStreamAllWindowedStream → DataStream

Aplica una función sobre toda la ventana

windowedStream.apply { WindowFunction}

Transformaciones para DataStream

Page 63: Workshop Apache Flink Madrid

Transformación Descripción

Window ReduceWindowedStream → DataStream

Aplica una función Reduce sobre una ventana.

windowedStream.reduce { _ + _ }

Window FoldWindowedStream → DataStream

Función de asociación usando un valor inicial sobre una ventana

val result: DataStream[String] =

windowedStream.fold("start", (str, i) => { str + "-" + i })

Aggregations on windowsWindowedStream → DataStream

Agregaciones sobre ventanas. Min devuelve el mínimo valor y MinBy el elemento que contiene el mínimo valorwindowedStream.sum(0) windowedStream.sum("key")

windowedStream.min(0) windowedStream.min("key")

windowedStream.max(0) windowedStream.max("key")

windowedStream.minBy(0) windowedStream.minBy("key")

windowedStream.maxBy(0) windowedStream.maxBy("key")

Transformaciones para DataStream

Page 64: Workshop Apache Flink Madrid

Transformation Description

UnionDataStream* → DataStream

Unión de 2 o más DataStreams creando uno DataStream único con todos loselementos.

dataStream.union(otherStream1, otherStream2, ...)

Window JoinDataStream,DataStream → DataStream

Join two data streams on a given key and a common window.

dataStream.join(otherStream) .where(0).equalTo(1)

.window(TumblingEventTimeWindows.of(Time.seconds(3)))

.apply { ... }

Window CoGroupDataStream,DataStream → DataStream

Cogroups two data streams on a given key and a common window.

dataStream.coGroup(otherStream) .where(0).equalTo(1)

.window(TumblingEventTimeWindows.of(Time.seconds(3)))

.apply {}

Extract TimestampsDataStream → DataStream

Extraer el timpstmap de un registro para usar ventanas que trabajan con semánticade tiempos

stream.assignTimestamps { timestampExtractor }

Transformaciones para DataStream

Page 65: Workshop Apache Flink Madrid

• Descargar el proyecto esqueleto MeetupMadrid Flink e importarlo en el IDE

https://onedrive.live.com/redir?resid=1F231B643ABC3A9C!11283&authkey=!AFsdm9PIjlkSrmM&ithint=file%2czip

• Esqueleto para procesar datos en tiempo real de la red social Meetup. Se leen las respuestas RSVG

• Analizar el código

o La clase MeetupStreamingSource lee datos de un WebSocket y los añade como una fuente de datos a Flink (SourceFunction)

o Se parsean los eventos (JSON) como un tipo de dato MeetupRSVGevent (Java)

• Ejecutar el Main

• Revisar la Web Admin (localhost:8081)

Ejercicio 4a DataStream API

Page 66: Workshop Apache Flink Madrid

• Sobre el flujo de datos entrante:

• Eliminar los objetos mal formados (alguno de sus campos a null)

• Contar los usuarios que han confirmado a cada evento en los últimos 10 segundos

• Contar los usuarios que han confirmado a cada evento en los últimos 20 segundos actualizando el resultado cada 5 segundos

• Contar los usuarios por países cada 5 segundos

• Calcular los Trending Topics (palabras semánticamente significativas más repetidos de los topic_name) teniendo en cuenta la información del último minuto y actualizando el resultado cada 10 segundos

Ejercicio 4b DataStream API

Page 67: Workshop Apache Flink Madrid

¡GRACIAS!

@ruben_casado

[email protected]