Existen diferentes anotaciones que podemos utilizar en nuestras entidades para dar formato a los valores de sus propiedades. En esta ocasión, hablaremos de las anotaciones @Type, @JsonFormat y @Temporal.



  • @Type: con esta anotación podemos cambiar el tipo de dato que viene de base de datos y convertirlo en otro tipo de dato. Como ejemplo, hemos añadido la propiedad ebook anotada en nuestra entidad Libro, con el fin de conocer si es un libro electrónico o no. En base de datos hemos utilizado una columna de tipo SMALLINT para representar valores boolean (0 y 1). Sin embargo, la propiedad en la entidad es de tipo boolean. Para realizar esta conversión de número a boolean tenemos que utilizar la anotación @Type especificando el tipo de conversión, que en este caso es org.hibernate.type.NumericBooleanType, tal y como se muestra en la línea 34. 
  • @JsonFormat: esta anotación permite formatear el valor de una propiedad en el momento de serialización de los datos. Hemos utilizado esta anotación para dar formato a la propiedad timestampInsercion, que indica la fecha de inserción de un libro en base de datos. Así, cuando obtenemos el JSON de un libro, la propiedad timestampInsercion se formateará siguiendo el patrón y el horario GMT especificado, tal y como se puede apreciar en la línea 38. 
  • @Temporal: sirve para especificar la precisión temporal de una propiedad de tipo Date. De esta forma, puede ser de tipo TIMESTAMP, TIME o DATE. En el ejemplo de la línea 39, hemos especificado una precisión de tipo TIMESTAMP, ya que es lo que almacenaremos en base de datos.


Pulsa aquí para acceder al código de esta entrada en mi repositorio Github
Spark dispone de un módulo para el procesamiento de consultas SQL. Estas consultas pueden utilizarse para manipular datos estructurados de lo más variado (JSON, CSV, Parquet, etc.) y sobre multitud de repositorios (bases de datos relacionales y no relacionales, Amazon S3, Hadoop, etc.). Además, es compatible con HiveQL, un lenguaje similar al conocido SQL que se ha convertido en indispensable a la hora de realizar operaciones sobre grandes cantidades de datos en plataformas Hadoop.



En este ejemplo, veremos cómo realizar consultas SQL sobre documentos en formato JSON. Para ello puedes descargar el fichero personas.json, donde en cada línea encontrarás la representación de una entidad Persona con los atributos nombre, edad y género. Es importante recalcar que en cada línea se encuentra una única representación de la entidad Persona en JSON, ya que de lo contrario el fichero no podría ser procesado por Spark. Debes copiar este fichero en "C:", para poder hacer referencia al mismo en el código del programa (línea 19) que leerá las personas contenidas en dicho fichero.

Para tener acceso al fichero y poder realizar las consultas, se crea un HiveContext. Esta clase dispone de métodos para leer archivos de diferentes tipos, en este caso JSON. Se puede especificar un fichero o un directorio que contiene ficheros JSON. En  nuestro caso será un único fichero. La lectura de este fichero devuelve una estructura de tipo DataFrame. Este tipo de dato es similar al utilizado en R y viene a representar los datos como si de una tabla de base de datos se tratara. El esquema de los datos y su tipología se infieren automáticamente por Spark, aunque para ganar en eficiencia pueden ser especificados de forma manual.

Una vez que tenemos el DataFrame, se creará una tabla temporal cacheada (líneas 22 y 23) sobre la que poder lanzar las consultas SQL. Una primera consulta obtiene todas las personas del fichero, y una segunda obtiene el número de personas del fichero. Los datos se devuelven en una estructura de tipo DataFrame.

A continuación hemos utilizado un método de agregación proporcionado por el DataFrame. Este método devuelve el máximo, mínimo y número de personas en un DataFrame.



Podemos visualizar los resultados con la función show() que dibujará por consola los DataFrame.



Pulsa aquí para acceder al código de esta entrada en mi repositorio GitHub
Hasta ahora, el método con el que obteníamos los libros existentes en nuestro repositorio nos devolvía un JSON con todos los libros almacenados. Esto puede ser un problema si nuestro repositorio contiene demasiados libros, por lo que sería interesante poder realizar una paginación y ordenación de resultados.

Afortunadamente, Spring Framework cuenta con los mecanismos necesarios, no sólo para obtener resultados paginados, sino también para obtener dichos resultados ordenados en base a unos campos determinados.



Para ello, lo primero que tenemos que hacer es cambiar la clase de la que extiende nuestro repositorio. Ahora deberá extender de la clase PagingAndSortingRepository, que ofrece además de los métodos ya comentados, la posibilidad de realizar una paginación y ordenación de resultados.




Además, el fichero dispatcher-servlet.xml debe ser modificado para que el sistema MVC de Spring Framework sea capaz de interpretar las peticiones de paginación y ordenación de forma correcta. Para ello se añadirá a la configuración el bean PageableHandlerMethodArgumentResolver.



También cambiará la llamada de la clase LibroFacade. Ahora, el parámetro de entrada será un objeto de tipo Pageable y devolverá una página de libros Page<Libro>



Este cambio de parámetros debe también ser reflejado en el controlador LibroController que inicia el procesamiento de la llamada a nuestra API RESTful.



Una vez que hayamos configurado nuestra API RESTful, podremos realizar llamadas que requieran de paginación de la siguiente forma
GET /libros?page=0&size=1

Para realizar llamadas con ordenación serán de la siguiente forma
GET /libros?sort=titulo,asc

Estos parámetros de paginación y ordenación, pueden combinarse también. A continuación se muestra un ejemplo del resultado obtenido con una llamada de paginación y ordenación como la que sigue.

http://localhost:8080/spring.rest.jpa.ii/v1/libros?page=0&size=2&sort=titulo,asc

Este resultado contiene ciertos parámetros adicionales que informan del total de páginas de las que se dispone (totalPages), el total de elementos (totalElements) o si es la última página (last), además de devolver los libros que pertenecen a la página de resultados solicitada.


En esta ocasión hablaré del tratamiento de excepciones y de los códigos de respuesta de nuestra API RESTful. Si recordamos la primera versión de la API, no teníamos ningún mecanismo que informara al cliente de que un determinado recurso no existía. Si por ejemplo realizábamos la petición GET /libro/87, el servidor no devolvería ningún resultado, pero el código de respuesta sería 200 (OK).

Para este caso concreto, lo correcto sería devolver un código de respuesta 404 (Not found). Puedes encontrar más información sobre los diferentes tipos de códigos de respuesta aquí



Para proveer a nuestros servicios de los mecanismos de tratamiento de excepciones y generación de códigos de respuesta necesarios, hemos creado un nuevo paquete de nombre spring.rest.jpa.ii.exception en el que se han implementado dos clases.
  • ResourceNotFoundException: es la excepción que extiende de RuntimeException y que se lanzará cada vez que se pida un recurso inexistente. En el constructor, podemos pasar el identificador del recurso que se ha solicitado pero que no existe en base de datos.


  • RestExceptionController: es el controlador que gestionará las excepciones lanzadas en los controladores de nuestra API. Es por eso que se ha utilizado la anotación @ControllerAdvice en la línea 21. La clase dispone de un método llamado resourceNotFound que se invocará para gestionar la excepción lanzada. El método utiliza las siguientes anotaciones.
    • @ExceptionHandler: con esta anotación informamos del tipo de excepción que gestionará el método, en este caso ResourceNotFoundException
    • @ResponseStatus: indicamos el código de respuesta a devolver, en este caso un 404.
    • @ResponseBody: para incluir un mensaje informativo en referencia al recurso inexistente.


De esta forma, si realizamos la petición GET /libro/87, se devolverá un código de respuesta 404 indicando que el recurso no existe, además de un mensaje del tipo "El recurso [87] no ha sido encontrado".


Pulsa aquí para acceder al código de esta entrada en mi repositorio Github
En esta segunda entrada sobre Apache Spark veremos como ejemplo el "Hello world" del mundo Big Data: contar las palabras de un texto y ver qué palabras son las más utilizadas en el mismo. Para ello, utilizaremos un archivo de texto que contiene todas las obras de William Shakespeare descargable desde aquí (aunque ya lo incluyo en el proyecto que puedes clonar desde mi repositorio GitHub).



Es importante señalar que para poder probar este ejemplo, necesitarás descargar un archivo llamado winutils.exe en este enlace, y copiarlo en la ruta "C:\hadoop\bin", de lo contrario la ejecución del código dará el mensaje de error Failed to locate the winutils binary in the hadoop binary path. Además, debes copiar el archivo shakespeare.txt en "C:".

En el código, hemos definido en la línea 20 una función para eliminar espacios en blanco adicionales, signos de exclamación, interrogación, puntuación, etc. con el fin de limpiar el fichero de texto. Esta función la hemos aplicado sobre el texto en la línea 30 utilizando la función map

Posteriormente obtenemos por cada línea las palabras y eliminamos aquellas que estén en blanco (línea 36) utilizando las funciones flatMap y filter. En la línea 38 obtenemos el número de palabras totales.

Ahora vamos a contar las apariciones de cada palabra en el texto, para lo cual utilizaremos el paradigma mapreduce mediante las funciones que nos ofrece Apache Spark. Para ello, convertiremos cada palabra en el par (palabra, 1) mediante la función map (línea 41). Posteriormente, utilizaremos la función reduceByKey para agrupar estos pares en base a su clave, que es la palabra, y contabilizar el número de apariciones de cada una sumando el valor de cada par (línea 42).

Para finalizar, imprimiremos por pantalla las 50 palabras que más se repiten en el texto. Para ordenar las palabras de mayor a menor número de apariciones, hemos utilizado en la línea 50 la función shortWith, que ordena en base al criterio establecido los pares (palabra, num. apariciones).


Pulsa aquí para acceder al código de esta entrada en mi repositorio GitHub
Seguimos con el tutorial para el desarrollo de una API RESTful con Spring Framework y JPA. Después de haber abordado aspectos básicos de la implementación de la API, en esta y siguientes entradas trataré aspectos algo más avanzados.

Para ello, he creado un nuevo proyecto con algunas modificaciones y mejoras sobre el anterior, con el fin de que sirva como ejemplo de todo lo que comentaré en siguientes entradas. En esta entrada, empezaré tratando algo fundamental en cualquier desarrollo de APIs RESTful, como es el versionado de los servicios de la API. 



Existen diferentes alternativas para implementar un mecanismo de versiones de nuestra API. Desde versionado por parámetro en la propia URL, petición de una versión específica de un recurso en el Header de la petición, etc. 

La estrategia que creo que es más sencilla de implementar y la que podemos ver en muchas APIs como Twitter y Facebook, es la basada en el versionado mediante la propia URL. En base a esta estrategia de versionado, las peticiones a nuestra API quedarán de la forma v1/libros, variando en función de la versión del servicio el path de la petición (v1, v2, etc.).

Para implementar el versionado, debemos modificar el controlador, especificando la versión en la raíz del path (línea 27). Además, nombraremos el controlador con un nombre específico para esa versión, en este caso libroController.v1 (línea 26). De esta forma, podremos disponer de diferentes versiones del controlador distribuidas en paquetes distintos de nuestro proyecto sin que entren en conflicto.



Pulsa aquí para acceder al código de esta entrada en mi repositorio GitHub
Es el turno de visualizar datos gracias a Kibana. Este entorno de visualización web es la tercera pata del stack ELK. Gracias a Kibana, podremos realizar diferentes visualizaciones en base a los datos indexados en Elasticsearch. Además, podremos configurar paneles de control o dashboards creados a partir de las visualizaciones creadas.

Para esta entrada, necesitaremos descargar y descomprimir Kibana.


Puesta en marcha de Kibana

Kibana se conectará a la instancia de Elasticsearch que ya hemos configurado en entradas anteriores, mediante el host y puerto configurados por defecto, por lo que tendremos que tener activa dicha instancia de Elasticsearch.

Para iniciar Kibana, accederemos a la carpeta bin dentro del directorio raíz de Kibana, y ejecutaremos el archivo kibana.bat. Accederemos a la consola de gestión en la URL http://localhost:5601/

Configuración de índices

El primer paso para empezar a trabajar con Kibana es configurar los índices de Elasticsearch desde donde se obtendrán los datos para ser visualizados. Esta configuración se realiza en la pestaña Settings. En nuestro ejemplo, los datos de cotización en bolsa los hemos almacenado en el índice de nombre logstash-bolsa-2015.

En la casilla para la especificación del índice, pondremos "logstash-bolsa-*". En vez de utilizar el nombre exacto del índice, hemos utilizado el asterisco como patrón, para que nos sirva para futuros datos referentes a otros años (p. ej. logstash-bolsa-2016).

Indicaremos también que nuestro índice dispone de una propiedad que almacena un dato de tipo timestamp, que en este caso corresponde a la fecha de cotización en bolsa. Indicaremos también que la propiedad que almacena dicho dato es @timestamp.

Crearemos el índice e inmediatamente veremos un listado con las propiedades que Kibana ha encontrado en los documentos almacenados en dicho índice. Podremos ver algunas propiedades adicionales de Elasticsearch junto con las propiedades de los valores de cotización en bolsa.



 

Exploración de datos

Para echar un vistazo rápido a los datos, podremos ir a la sección Discover para realizar algunas consultas. Disponemos de una caja de texto con un asterisco, que indica que queremos obtener todos los datos indexados.

Puesto que los valores de cotización en bolsa corresponden al año 2015, tendremos que configurar el rango temporal con el control disponible arriba a la derecha. Mediante la opción Quick -> Previous year podremos ver un gráfico que refleja el histograma de los datos recogidos ese año y un listado con una muestra de los mismos.

También podemos filtrar los datos en base al valor de una propiedad. Por ejemplo, podemos especificar en el espacio de búsqueda "company: YAHOO", con lo que veremos únicamente los datos correspondientes a las acciones de Yahoo.


  

Visualización de datos

Vamos a crear ahora una visualización de datos, mediante la pestaña Visualize. En esta pestaña, veremos un listado de posibles gráficas. En este caso, vamos a crear una gráfica de tipo Line Chart, con el fin de comparar el precio de las acciones de cada compañía en el momento de apertura de mercados. Pinchando en Line Chart y seleccionando From a new search, accederemos a la configuración de la gráfica.

En el eje Y, elegiremos como métrica el máximo sobre el campo open. De esta forma, el eje Y representará los valores de las acciones en el momento de apertura de mercados. Para el eje X, crearemos lo que se denominan buckets. Los buckets son una especie de "cubos" donde se "insertarán" o agruparán los datos en base a una serie de parámetros. 

En nuestro caso, crearemos un bucket de tipo Date histogram sobre la propiedad @timestamp, para que los datos se puedan agrupar en base a la fecha en la que fueron obtenidos. Si dejáramos así la configuración y ejecutáramos la visualización (botón verde con el play) veríamos una gráfica con una sola línea, que correspondería a los valores de Google, ya que es la que dispone de los valores más altos.

Para solucionar el problema, añadiremos un sub-bucket sobre el ya configurado. Este sub-bucket será de tipo Split Lines, para diferenciar las líneas correspondientes a Google y Yahoo. Para ello, crearemos un par de filtros, que servirán para dividir la línea en dos. Los filtros pueden configurarse en base a valores de las propiedades, por lo que crearemos uno de tipo "company : YAHOO" y otro de tipo "company : GOOGLE". Ejecutando otra vez la visualización, veremos que ahora aparecen dos líneas, una para cada compañía. Podremos guardar la visualización para su posterior uso o consulta.


Creación de un panel de control o dashboard

En la pestaña Dashboard podemos crear un panel de control con las gráficas que hemos guardado anteriormente. En este caso, crearemos un panel de control que incluya la visualización creada anteriormente. Podemos situar cada visualización en el lugar que creamos pertinente y con las dimensiones que queramos, por lo que se permite una flexibilidad total a la hora de componer nuestros paneles de control. Estos dashboard podemos también guardarlos e incluso incrustarlos en cualquier web externa mediante la opción Share, la cual nos facilita un código de incrustación.


 

Conclusiones

Kibana permite realizar visualizaciones de datos de una forma sencilla y flexible. Dispone de multitud de tipos de gráficas y parámetros de configuración, que hacen que pueda adaptarse a cualquier dominio y necesidad de visualización de datos. Es importante recalcar, que estas visualizaciones se actualizan en tiempo real a medida que nuevos datos son indexados en Elasticsearch. Si los tipos de gráficos no fueran suficientes, se pueden desarrollar plugins de forma sencilla para crear los gráficos que podamos necesitar en cada caso.

En siguientes entradas crearé un ejemplo más completo con el stack ELK para la indexación y visualización de tweets de la red social Twitter, así que puedes suscribirte a mi blog para no perder detalle!