Primeros pasos con Apache Drill

¿Qué es apache drill?

Es un motor de consultas open-source para exploración de fuentes de datos con grandes volúmenes de datos. Apache drill nos permite realizar análisis de alto rendimiento sobre datos semiestructurados sin dejar de ofrecer la familiaridad y el ecosistema de la norma ANSI SQL. Apache drill a su vez posee integración con Hive y HBase.

Apache drill a menudo es comparado con Hive y con Impala, por su alto rendimiento por trabajar con ficheros .csv y .json, así como también porque por medio de estas podemos efectuar consultas en HBase, pero hay un aspecto donde drill sobresale y es que puede conectarse a otros gestores de bases de datos como por ejemplo MySQL y MongoDB.

¿Cómo conocí Apache drill?

Me topé con apache drill por casualidad en el 2015, debido a las circunstancias y dificultades con las que trabajábamos, teníamos ordenadores plataformas que no nos permitían instalar nada y como tarea teníamos que hacer cruce de información de grandes ficheros .csv con sistemas de bases de datos relacionales. Los ficheros .csv eran tan grandes que ni siquiera podíamos visualizarlos con excel ni con atom y apache drill termino siendo una herramienta estupenda para poder realizar exploración sobre los datos y eso que lo utilizamos en modo embebido en nuestro ordenadores.

Instalación

Apache drill tiene 2 tipos de instalación dependiendo si será en un cluster o si será en un único nodo, nosotros haremos la de un único nodo, la cual es muy sencilla ya que solo es necesario descomprimir el fichero descargado y ejecutar el  fichero ./drill-embebed el cual esta en la carpeta /bin de nuestra instalación.

Este último paso abrirá una consola donde podremos ejecutar sentencias sql y además se levantará un cliente web al que podremos acceder desde cualquier navegador en la ruta http://localhost:8047

apache drill web client

apache drill web client

Ahora vamos a empezar a jugar con drill, para ello crearemos un fichero json que denominaremos cliente_banco.json con los siguientes datos:

También crearemos un fichero csv con los datos de los clientes y lo llamaremos clientes.csv:

Ahora que empiece la diversión, lo primero que haremos será consultar los datos del fichero clientes.csv como si fuera una tabla con SQL utilizando el cliente Web de drill, para ello será necesario ir a la ruta http://localhost:8047/query

Una vez allí ejecutaremos la siguiente sentencia:

SELECT * FROM dfs.ruta_fichero/clientes.csv

resultado query csv en drill

resultado query csv en drill

El resultado no se puede apreciar muy bien además que se ve que asume la cabecera del fichero csv como si fuese un registro, para mejorar esto, será necesario hacer una pequeña modificación en la configuración. Apache drill funciona con plugins donde se almacena toda la configuración de las conexiones con ficheros del filesystem, de gestores de bases de datos, tipo mongoDB, MySQL, etc. por ende será necesario que editemos la configuración del plugin de filesystem para que tome en cuenta la cabecera del fichero csv (NOTA: Aquí también podríamos configurar el tipo de separador ya sea «,»o «;» o «|» entre otros).

Para realizar la actualización de la configuración deberemos ir a la ruta http://localhost:8047/storage y hacer clic en el botón «Update» del plugin dfs.

storage

storage

Allí veremos un json utilizado para la configuración y buscaremos el elemento «csv» dentro del objeto «formats» y le añadiremos el atributo «skipFirstLine»: true como se muestra en la siguiente imagen y procederemos a actualizar el plugin pulsando el botón «Update».

configurando plugin dfs

configurando plugin dfs para que no tome en cuenta la primera linea del csv

Si intentamos de nuevo la consulta veremos como es obviada la cabecera del fichero csv, aunque aún no vemos el resultado como una tabla, para eso utilizaremos alias para identificar a cada columna al momento de efectuar la consulta de la siguiente forma:

SELECT columns[0] as ID, columns[1] as NOMBRE, columns[2] as APELLIDOS, columns[3] as PROVINCIA FROM dfs.ruta_fichero/clientes.csv

Obteniendo lo siguiente:

resultado de la consulta

resultado de la consulta

Vamos a profundizar aún más y ahora realizaremos un join entre los datos del fichero csv y del fichero json, ejecutando la siguiente consulta:

SELECT tablaCSV.columns[0] as ID, tablaCSV.columns[1] as NOMBRE, tablaCSV.columns[2] as APELLIDOS, tablaCSV.columns[3] as PROVINCIA, tablaJSON.BANCO FROM dfs.ruta_fichero/clientes.csv tablaCSV
LEFT JOIN dfs..ruta_fichero/cliente_banco.json tablaJSON
ON tablaCSV.columns[0] = tablaJSON.ID

Obteniendo:

resultado del left join

resultado del left join

Apache drill nos ofrece a su vez más posibilidades como por ejemplo crear tablas en formato parquet  a partir de un json o de un fichero csv. Apache drill es una herramienta que me gusta mucho pero también cuenta con algún aspecto a mejorar, por ejemplo me gustaría poder utilizar la cabecera de un fichero csv como nombre de columna al efectuar consultas y esto no funciona del todo bien, de hecho hice unas pruebas y fue así como me percate de este pequeño error que estoy seguro (y espero) se solucione pronto.

Para que la cabecera de un archivo csv sea tomada en cuenta como nombre de columna de una tabla es necesario modificar la configuración del plugin dfs, al igual que lo hicimos antes para que no tomase en cuenta la primera fila del archivo, editando el formato csv así como en la siguiente imagen.

config dfs plugin

configurando dfs plugin para que reconozca la cabecera de los ficheros csv

De nuevo repitamos la consulta que hacíamos al principio:

SELECT * FROM dfs.ruta_fichero/clientes.csv

Vemos como de inmediato sin haber utilizado alias en la consulta el resultado es devuelto como una tabla

Si ahora repetimos la consulta veremos como la salida de los resultados ha cambiado, dándonos una perspectiva de que tenemos una tabla, utilizando la cabecera del fichero csv como la cabecera de la tabla de resultados

consulta de todos los campos

consulta de todos los campos

Además al igual que con ejemplos anteriores podemos efectuar join con otras tablas independientemente en el formato o fuente que se encuentren (son, csv, parquet, mysql, etc…), el problema (o error) esta cuando intentamos consultar por un campo en especifico alguno puede que no devuelva nada como por ejemplo si efectuamos la siguiente consulta:

SELECT ID, NOMBRE FROM dfs.ruta_fichero/clientes.csv

consulta de ID y NOMBRE

consulta de ID y NOMBRE

 

Esto me pareció tan extraño que intente jugar con distintos parámetros de configuración e incluso con la forma de realizar la consulta y no pude solventar este comportamiento por lo que publiqué  este error en stackoverflow por si estaba haciendo algo mal y alguien podía echarme una mano.

No quiero que lo último los desanime a probar la herramienta ya que esta cuenta con muchas bondades que dan para redactar unas cuantas entradas más, espero que hayan podido seguir todos los ejemplos y tener una perspectiva de lo que podemos alcanzar con la herramienta.

ACTUALIZACIÓN 28-09-2016:

Al haber quedado con la inquietud del mal funcionamiento al ejecutar la consulta sobre el csv indicando como columnas la cabecera del fichero, me decidí a escribir a lista de usuarios de apache drill por si en dado caso me estaba topando con un bug (cosa extraña porque llevaría así al menos 3 releases) y ellos me han dado la respuesta, el problema estaba en el espacio en blanco inmediatamente después de la coma, por lo cual al reformular la consulta y hacerla de la siguiente manera funcionó a la perfección:

SELECT ID, ‘ NOMBRE’ FROM dfs.ruta_fichero/clientes.csv

Pero otra forma quizás más elegante aún es que se eliminase el espacio después de la coma en la cabecera del archivo csv, de esa manera  basta con que coloquemos los nombres de las columnas sin necesidad de encerrarlas entre comillas al momento de formular la consulta.

SELECT ID, NOMBRE FROM dfs.ruta_fichero/clientes.csv

Estadística simple con Spark V2

Sigo con mi pruebas con lo nuevo (y no tan nuevo de Spark 2), hoy comparto con ustedes una versión 2 de mi anterior post Estadística simple con Spark, pero en esta ocasión realizado con Spark 2.

¿Que tiene de nuevo esta versión?

Primeramente utiliza el módulo spark-csv lo cual nos hace más simple la carga del fichero en un Dataset. Segundo, que no manipulamos en ningún instante RDD alguno, sino que por el contrario estamos trabajando con DataFrames representados mediante la clase Dataset. Entre las cosas nuevas que contempla esta versión hecha en Spark 2 es que mientras antes al realizar un groupBy sobre un DataFrame esto nos devolvía un GroupedData ahora nos devuelve un RelationalGroupedData, esto debido a un cambio de nombre que se le ha dado a partir de esta nueva versión de Spark.

Esta nueva versión realizada con SparkSQL con Datasets tiene varias ventajas, la primera es simplicidad, es mucho mas simple, mas fácil de entender el código además de mas corto, de hecho con menos lineas obtuve más información que con la versión elaborada con RDD’s, es decir, es mas versátil. Por otro lado aunque hay que tener algo de nociones de conjuntos lo interesante es que esta versión esta libre de código SQL.

Sin más dilación he aquí el código y el enlace al proyecto en Github.

Para que comparen los resultados obtenidos aquí con respecto a la entrada anterior dejo un pantallazo de lo obtenido al ejecutarlo en mi local.

promedios por distrito

promedios por distrito

Otras agregaciones por distrito

Otras agregaciones por distrito

Total personas por distrito

Total personas por distrito

Primer ejemplo con apache Storm

Apache Storm es un framework de procesamiento distribuido de eventos. Empresas como twitter utilizaron Storm desde el 2011 aunque posteriormente lo reemplazó por Heron en el 2015.

Actualmente me encuentro trabajando en una aplicación construida con Apache Storm y quiero compartir con ustedes mi primer ejemplo con Apache Storm el cual es bastante simple pero cumplio su cometido que era el iniciarme en este framework y entender sus componentes principales.

Necesitaremos descargar rabbitMQ la versión 3.5.7.

Una vez hayamos instalado rabbitMQ (es solo cuestión de descomprimir) vamos a habilitar un plugin (un cliente web) donde podremos de forma sencilla monitorizar las colas, entonces nos ubicamos en la siguiente ruta ruta_instalacion_rabbitmq/sbin/ y desde allí ejecutamos el siguiente comando

./rabbitmq-plugins enable rabbitmq_management

Este comando habilitará el cliente web que nos permitirá monitorizar las colas, los exchanges  incluso manipular las colas pudiendo ingresar elementos a las colas, sacar elementos e incluso purgar las colas. Paso siguiente iniciaremos el rabbitMQ con el siguiente comando:

./rabbitmq-server

Inmediatamente después desde un navegador nos dirigimos a la dirección http://localhost:15672

rabbitmq overview

rabbitmq overview

Una vez allí crearemos una cola para hacer nuestro ejemplo y la llamaremos «data».

agregar cola en rabbitmq

agregar cola en rabbitmq

Ahora deberíamos ser capaces de ver la única cola de nuestro sistema. Clicando en ella podríamos incluso agregarle mensajes por medio de la interfaz gráfica (si lo desean hagan la prueba y verán como cada uno de los mensajes que agreguen se irán encolando), pero la inserción de mensajes en la cola lo haremos mediante un pequeño programa Java.

cola data

cola data

Ahora un poco de teoría para conocer acerca de Apache Storm.

¿Qué es Apache Storm?

Es un framework de computación distribuida en tiempo real, escrito en su mayoría en Clojure. Storm es similar a la forma como Hadoop ofrece un conjunto de primitivas generales para hacer el procesamiento por lotes, también ofrece un conjunto de primitivas generales para hacer cómputos en tiempo real. Storm es simple, se puede utilizar con cualquier lenguaje de programación.

Las aplicaciones de Storm son creadas como topologías en la forma de DAG (Directed Acyclic  Graph) con spouts y bolts actuando como los vertices del grado. Las aristas en el grafo son llamados streams y dirigen la data de un nodo a otro. Juntos, la topología actúa como una tubería de transformación de datos.

Los spouts son fuentes de flujo (streams) en una topología. Los spouts generalmente leerán tuplas desde una fuente externa y las emiten dentro de la topología.

Un bolt es donde se realiza todo el procesamiento de una topología, pueden hacer cualquier cosa, desde filtrado, funciones, agregaciones, joins, comunicarse con bases de datos y mucho más.

El ejemplo que hice y compartiré a continuación con ustedes será bastante simple, estará constituido por un spout que leerá de una cola rabbitmq (la cola data que creamos anteriormente) y ese mensaje lo insertará en la topología para posteriormente al recibirlo el bolt mostrarlo por linea de comandos (ya luego si ustedes lo desean lo que podrían hacer es que en vez de mostrarlo por linea de comandos volcar ese mensaje en otra cola de rabbitmq).

El programa java que se encarga de insertar mensajes a la cola

El Spout que leerá de la cola rabbitMQ

El bolt que leerá los datos que han sido insertados en la topología por el Spout

Definición de la topología

Para ejecutar nuestro ejemplo y verlo funcionando debemos ejecutar 2 clases (el orden sería indistinto):

  • SendMessagesToRabbit
  • RabbitMQTopologyExample

Al ejecutar la clase SendMessagesToRabbit, podremos ver en el cliente Web de RabbitMQ como la cola tendrá 10000 mensajes encolados. Al ejecutar la topología (ejecutando la clase RabbitMQTopologyExample) podremos ver como los mensajes se van desencolando y a su vez por linea de comandos (por ejemplo de nuestro editor) veremos los mensajes que en teoría el bolt leyó y procesó.

Espero que les sea de utilidad y disfruten con este framework, desde mi punto de vista es sencillo y funciona bien, incluso la nueva herramienta que utiliza Twitter posee retrocompatibilidad con Storm por lo cual se podría empezar con un ejemplo de este tipo.

Clic aquí para ir al repositorio github.

Primer ejemplo con apache spark

Hace algunas semanas atrás que empezamos a trabajar con apache spark en el máster, brevemente les contare mis impresiones desde mi punto de vista como principiante.

Apache spark me gusto, ¿por qué? porque se puede programar en Scala (además de Python y Java),  la API de Scala lo simplifica mucho y la cantidad de código a teclear es (considerablemente) menor a la necesaria para hacer la misma tarea en Java, aunque aquí debo hacer un paréntesis, ya que con la entrada de Java 8 y las lambda expresión la cantidad de código será menor pero insisto la API de Scala a mi modo de ver lo hace mas sencillo.

Nos permite hacer operaciones con mucha data (quizás no Big Data, es decir no hablamos de TeraBytes) sin necesidad de usar Hadoop, me gustaría hacer hincapié en esto ya que muchos piensan que Big Data es Hadoop y NO, no es así, mi concepto de Big Data es un poco mas amplio y contempla mas cosas, aquí me refiero específicamente a la API MapReduce de Hadoop la cual es mas complicada de usar que la de Spark, no obstante si necesitamos trabajar con una cantidad de datos considerable que requiera del uso de HDFS, podemos desde Spark acceder a este sistema de archivo u algún otro como por ejemplo Amazon S3.

Por último decirles que Spark es mas rapido, esto se debe a su arquitectura, ya que este trabaja en memoria (todo en memoria si tiene la capacidad de cargar todos los datos por completo) y pues si llegamos a hacer varias tareas (lo que técnicamente sería reutilizar los RDD ya guardados en memoria) con los datos en memoria es cuando mas jugo se le sacará a Spark.

Sinceramente si alguien discrepa de mi o coincide me entusiasmaría mucho que comparta su opinión ya que todo este mundo que envuelve el Big Data me tiene super enganchado.

 Ahora bien vamos con los ejemplos, estas formaban parte de la primera tarea de Spark que tuvimos que realizar, y consiste en 2 ejemplos:

  1. Dado un fichero de texto en formato csv con información de medallistas olímpicos, obtener el numero de medallas por edad.
  2. Dado el mismo fichero de texto anterior, y un esquema de puntuación por tipo de medalla obtener un ranking de medallistas olímpicos.

He aqui el código:

 

Una última cosa que es bueno saber para aquellos que como yo están empezando con Spark y sus RDD, Los RDD tienen 2 tipos de operaciones: transformaciones y acciones, las primeras son operaciones que como resultado nos devuelven otro RDD y las acciones son aquellas que hacen «algo» sobre los datos como por ejemplo el foreach de mi código,  utilizado para mostrar por pantalla los valores finales, además los RDD (como hasta ahora lo entiendo) son las instrucciones a realizar sobre los datos, mas no almacenan la información, además estás instrucciones no se realizan de inmediato, sino que al contrario estos tienen un funcionamiento lazy, esto significa que se ejecutan cada vez que se realiza una operación de tipo acción.

Otra sugerencia, no duden en cacharrear con la consola de spark, de hecho el primer ejercicio lo llegue a hacer por la consola (sin los JavaBeans) y el practicar por aquí si que ayuda a conocer los operaciones a utilizar sobre los RDD.

Aquellos interesados en descargar el código, les dejo la dirección del ejercicio en mi repositorio github

El esqueleto del ejercicio esta en el repositorio del que fue nuestro profesor y pueden acceder a el haciendo clic aquí.

Cualquier material, idea o contenido que quieres compartir, no dudes en hacerlo, ya que bien recibido será. Ahora si para cerrar les dejo el enlace a un libro que hasta ahora me esta pareciendo muy bueno para aprender Spark (además con ejemplos elaborados en Java, Scala y Python).