Apache Spark para principiantes

BI Geek / Big Data  / Apache Spark para principiantes

Apache Spark para principiantes

En blogs anteriores se pudo ver tanto la historia del procesamiento distribuido como los frameworks más importantes del mercado. El objetivo con esta nueva serie es poder enseñar desde una perspectiva más práctica el uso de uno de estos frameworks, Apache Spark.

Apache Spark es un framework de procesamiento distribuido que hace uso del paradigma de programación MapReduce para realizar computación distribuida a través de varios nodos.

En todas estas series utilizaremos como lenguaje de programación Scala, aunque Apache Spark también provee API para Python y Java. La elección de Scala no es arbitraría. Scala, al igual que Pyhton, es un lenguaje funcional que permiten implementar el paradigma MapReduce de manera más sencilla y rápida. Scala trabaja sobre la JVM, lo que nos permite disponer de las múltiples librerías creadas para Java.

WordCount

Al igual que en programación no distribuida, donde se suelen poner ejemplos como el Hello World para dar a conocer los comandos básicos de un lenguaje o framework, en programación distribuida se utiliza el ejemplo WordCount. Este ejemplo consiste en poder contar las apariciones de cada una de las palabras de un fichero de texto.

Para ello, recordando posts anteriores, hacemos uso de las funciones Map y Reduce:

  1. Map: Dividiremos las frases en palabras y las asignaremos un 1.
  2. Reduce: Agregaremos las palabras y sumaremos el contador asignado anteriormente, de tal modo que las palabras que sean iguales se sumarán dando como resultado el número total de palabras iguales.
val textFile = spark.sparkContext.textFile("ruta/del/ficher.txt")

En primer lugar, utilizando el context de Spark (spark), accedemos al context SparkContext que nos provee del método textFile que permite la lectura de un fichero y convertirlo en un RDD.

val counts = textFile.flatMap(line => line.split(" "))
.map(word => (word, 1))
.reduceByKey(_ + _)

Una vez tenemos el RDD es necesario realizar un split para dividir cada frase en palabras. La idea es que por cada registro original se generen n registros donde n es el número de palabras en cada registro. Al querer generar más de un RDD por cada uno de los RDD es necesario utilizar la función flatMap en lugar de la función map.

Después, con la función map, les asignamos el 1 generando una tupla clave-valor. Finalizamos utilizando la función reduceByKey que permite agregar los datos por la clave (Word) pasándole una función de agregación, en este caso, la suma de sus valores.

counts.collect.foreach(println _)

Por último, con la función collect, transformamos el RDD en un Array, el cual podemos recorrer e imprimir.

Ejecución

Una vez escrito el código, existen varias formas de ejecutarlo. La forma más sencilla es haciendo uso de la spark-shell. Este programa abre una consola de spark donde está creado automáticamente el contexto de Spark y podemos ejecutar código scala directamente.

spark-shellPara ello, ejecutamos el programa /bin/spark-shell y lo único que hay que hacer es copiar y pegar el código.

Al iniciar el programa spark-shell, se inicializan dos contextos, el  Spark session (spark, disponible a partir de la versión 2.0 de Apache spark) y el Spark context (sc).2

Mediante estos contextos, seremos capaces de genearar un RDD a partir de un fichero almacenado para poder contar las apariciones de cada palabra.

Para ello, ejecutamos las sentencias anteriormente explicadas (con pequeñas modificaciones para la correcta ejecución). Tras ejecutar cada una de las sentencias, podemos ver como se van creando los RDDs correspondientes.

Por último, podemos ver el resultado de la ejecución: Un conjunto de tuplas (palabra, numero de ocurrencias).3

Palabras con mayor ocurrencia

Para imprimir las palabras con mayor ocurrencia, será necesario ordenar las palabras por la segunda posición de la tupla, conocido también como valor. La función para ordenar es denominada sorterByKey, por lo que es necesario intercambiar las posiciones de cada una de las tuplas para ordenar por el número de ocurrencia.

El nuevo código sería el siguiente:

val counts = textFile.flatMap(line => line.split(" "))
                .map(word => (word, 1))
                .reduceByKey(_ + _)
		.map(item => item.swap)
                .sortByKey(false)
		.take(10)
counts.foreach(println _)
  • La función swap intercambia el orden de una tupla. Es necesario usar la función map para aplicar esta función a cada una de las tuplas que forman el RDD.
  • La función take funciona como la función collect pero recibiendo como parámetros el número de registros del RDD que formarán parte del array.

Por último, tras la ejecución obtendremos el siguiente resultado:

4Una lista ordenada de las 10 palabras que más aparecen en el quijote (el elemento vacío corresponde a doble espacio).

Próximas entradas

En próximas entradas de esta serie, veremos cómo crear programas usando Apache Maven, una potente herramienta para la gestión y creación de proyectos java. También veremos otro método de ejecución que nos permitirá ejecutar archivos jar que crearemos mediante Maven.

Consultor Senior en Business Intelligence y Big Data.