martes, 17 de octubre de 2017

Probando software Big Spatial Data (Hadoop + HBase + GeoWave + GeoServer) sin morir en el intento :-)

El propósito de este artículo es mostrar los resultados obtenidos probando la integración de software Big Data y herramientas con funcionalidad Geoespacial. Es de resaltar que la integración de los componentes utilizados, todos ellos open source, nos permite además publicar servicios WEB conforme a los estándares OGC (WMS, WFS, WPS...).




El artículo describe los pasos de instalación, configuración y desarrollos realizados para obtener finalmente un visor WEB mostrando las concentraciones de NO2 en alrededor de 4.000 estaciones de Europa en un espacio de tiempo de cuatro meses (Con medidas registradas cada hora), unos 5.000.000 de registros. Sí, lo sé, ese volumen de datos no es nada "Big Data", pero parece suficiente para evaluar el comportamiento al consumirlo en aplicaciones cliente utilizando filtros espaciales y/o temporales (Puede ver el vídeo vinculado a la imagen).

El artículo no va a profundizar en el conocimiento de los componentes utilizados, todos los productos ya publican buena documentación desde el punto de vista de usuario y de desarrollador, simplemente quiere ofrecer experiencias y una guía orientativa que aglutine recursos de cada una de las herramientas utilizadas. Por ejemplo, la parte de GeoWave, y su integración con GeoServer, es un calco de las guías de usuario y desarrollador que existen en su portal WEB de producto.


Esquema de los datos

Los datos han sido obtenidos de la Agencia Europea de Medio Ambiente (EEA). Puede buscar aquí información y visores de mapas de esta u otras temáticas, o mejor, use otros datos que sean más de su interés. El proyecto GDELT es otro recurso que ofrece información masiva.

El esquema de los datos utilizados es sencillo; la entrada de información es un conjunto de archivos CSV (Ficheros de texto con sus atributos separados por comas) con puntos en coordenadas geográficas (Latitud/Longitud) que localizan el sensor, la fecha de medida, y el valor de concentración de NO2. Hay otros valores que son secundarios para esta prueba.



Arquitectura Software

La prueba ha consistido en encadenar diferentes herramientas, cada una de las cuáles publica datos y funcionalidad al siguiente componente de la arquitectura final. El diagrama de aplicaciones comienza con Hadoop y su HDFS, HBase para su mapeo como base de datos, el estupendo GeoWave como conector entre ella y el conocido GeoServer como servicio WEB que implementa varios estándares OGC, y ya un cliente final que consuma los datos utilizando tecnología WEB estándar (Leaflet y la librería Heatmap.js por ejemplo) para mostrar los resultados.




Por componentes:


Apache Hadoop

Apache Hadoop es, si buscamos un poco en Google, ... un framework que permite el procesamiento de grandes volúmenes de datos a través de clusters, usando un modelo simple de programación. Su diseño permite pasar de pocos nodos a miles de nodos de forma ágil. Hadoop es un sistema distribuido utilizando una arquitectura Master-Slave, usando para almacenar su Hadoop Distributed File System (HDFS) y algoritmos de MapReduce para hacer cálculos.

HDFS es el sistema de almacenamiento, es un sistema de ficheros distribuido. Fue creado a partir del Google File System (GFS). HDFS se encuentra optimizado para grandes flujos y trabajar con ficheros grandes en sus lecturas y escrituras. Su diseño reduce la E/S en la red. La escalabilidad y disponibilidad son otras de sus claves, gracias a la replicación de los datos y tolerancia a los fallos.


Nuestra prueba utilizará Hadoop y su HDFS como repositorio destino de los datos que vamos a almacenar y explotar finalmente en la aplicación de usuario. Puede consultar aquí recursos del proyecto, y bucear en toda la documentación que ya existe en Internet para conocerlo en profundidad.

Para las pruebas he utilizado Windows como sistema operativo. No se distribuye una versión para este SO pero hay una estupenda guía aquí para compilar Hadoop (Usando Maven) y para configurar los ficheros necesarios para por lo menos tener un sistema de nodo simple. Evidentemente un entorno real de producción requerirá configurar un cluster multi-node distribuido, utilizar alguna distribución ya configurada (Hortonworks...) o evaluar el salto a Cloud (Amazon S3, Azure...).

Seguidos los pasos de la guía; compilado Hadoop con Maven, editados los ficheros de configuración y establecidas las variables de entorno, podremos probar en consola que todo está correcto con el comando...

> hadoop version


Arrancaremos entonces los "demonios" que ejecutan los nodos "namenode", "datanode", y el gestor de recursos "yarn".

> call ".\hadoop-2.8.1\etc\hadoop\hadoop-env.cmd" 
> call ".\hadoop-2.8.1\sbin\start-dfs.cmd" 
> call ".\hadoop-2.8.1\sbin\start-yarn.cmd"

Ahora podemos ver el administrador de Hadoop en el puerto establecido en la configuración, en mi caso es el puerto 50.070:




Apache HBase

Apache HBase es, de nuevo si buscamos en Google, ... una base de datos de código abierto no relacional y con versiones que se ejecutan sobre Amazon S3 (con EMRFS) o el sistema de archivos distribuidos de Hadoop (HDFS) y está diseñada para brindar acceso en tiempo real aleatorio y estrictamente uniforme a tablas con miles de millones de filas y millones de columnas.

Los datos se almacenan en las filas de una tabla, mientras que los datos de una fila se agrupan por familia de columnas. HBase es una base de datos sin esquemas en el sentido de que no es preciso que ni las columnas ni el tipo de datos almacenados en ellas se definan antes de usarlos.


Puedes leer aquí para poner HBase en marcha. De nuevo en consola, podemos verificar la instalación...

> hbase version 


Arrancamos HBase:

> call ".\hbase-1.3.1\conf\hbase-env.cmd" 
> call ".\hbase-1.3.1\bin\start-hbase.cmd"

Veamos finalmente el administrador de HBase, en mi caso en el puerto 16.010:


Bien, en este punto ya tenemos el entorno "Big Data" corriendo, es momento de ir preparando las herramientas de servidor que dan la funcionalidad Geoespacial; GeoWave y GeoServer, seguimos...


LocationTech GeoWave

GeoWave es una librería software que actúa de conector entre el entorno distribuido, Hadoop + HBase en nuestro caso, y un software Geoespacial como GeoServer. Guau! esto sí que es un conector! :-)



En términos técnicos, esta librería implementa realmente un "Data Provider" vectorial de GeoTools para leer los features (fenómenos geográficos) cargados en el sistema distribuido. Cuando añadimos a GeoServer el correspondiente plugin, el usuario verá tres nuevos tipos de "Data Store" con el que configurar el acceso a capas cargadas en sistemas de este tipo.




Actualmente están soportados tres "Data Store" a bases de datos tipo "Big Data", Apache Accumulo, Google BigTable y HBase, que es la que estamos usando.

Dejemos GeoServer para más adelante y volvamos a la gestión de los datos con GeoWave. Según las guías de usuario y desarrollador de GeoWave, debemos primero definir los índices primarios o secundarios que tendrán las capas de datos, y luego cargar la información al sistema "Big Data" (Recordad, Hadoop + HBase para mi caso).

De la guía de desarrollador, compilaremos con Maven el framework de tools de GeoWave para cargar los datos sobre HBase:

> mvn package -P geowave-tools-singlejar

y el plugin que incluiremos en GeoServer:

> mvn package -P geotools-container-singlejar

Para ejecutar cómodamente comandos de GeoWave, me he definido una variable de entorno con el comando base:

> set GEOWAVE=java -cp "%GEOWAVE_HOME%/geowave-deploy-0.9.6-SNAPSHOT-tools.jar" 
  mil.nga.giat.geowave.core.cli.GeoWaveMain

Ahora fácilmente podremos correr los comandos de configuración y carga con escribir simplemente %geowave% [...]. Comprobamos la versión del software para ver si todo está correcto:

> %geowave% --version 


Ok, ya podemos registrar los índices espacial y temporal que tendrá nuestra capa. Para este test el modo de acceso desde la aplicación cliente será estableciendo un filtro espacial, la vista actual en el mapa (Cruce con un BBOX en términos técnicos) y un filtro temporal para recuperar sólo las observaciones de NO2 de una determinada fecha.

Vamos con ello, registremos los dos índices:

> %geowave% config addindex 
   -t spatial eea-spindex --partitionStrategy ROUND_ROBIN 

> %geowave% config addindex 
   -t spatial_temporal eea-hrindex --partitionStrategy ROUND_ROBIN --period HOUR 

Y añadimos también lo que en terminología GeoWave se denomina "store" de la capa:

> %geowave% config addstore eea-store 
  --gwNamespace geowave.eea -t hbase --zookeeper localhost:2222

Atención, en el comando anterior, 2.222 es el puerto donde he publicado el Zookeeper de mi HBase.

Ya podemos cargar datos. Nuestra fuente de datos son ficheros CSV, así que usaremos el parámetro -f con "geotools-vector" para indicarle a la herramienta de carga que la librería GeoTools averigüe el proveedor de datos con el que leer la información. Como se puede ver en la documentación, hay otros formatos soportados y nada impide implementar por nosotros mismos uno nuevo que cubra nuestros propios requerimientos.

Entonces, para un CSV:

> %geowave% ingest localtogw -f geotools-vector
  ./mydatapath/eea/NO2-measures.csv eea-store eea-spindex,eea-hrindex

Y tendremos cargada la capa de puntos, hasta aquí sin problemas, o sí  :-p, el data provider que viene con GeoTools para leer ficheros CSV tiene unas pequeñas carencias que he intentado mejorar. En el estado actual del código, el lector no soporta atributos de tipo fecha (y tampoco los tipos "boolean"), los trata como simples "string". Eso es inaceptable para nuestro requerimiento de que la fecha es un atributo principal de la capa, así que implementamos este tipo de atributo en el código original. Además, la verificación del tipo de atributo está de tal forma que el código verifica los valores de todos los registros del fichero. Este comportamiento es más seguro para inferir el tipo de valor, pero muy lento para ficheros de tamaño considerable (Miles o cientos de miles de filas). Si el fichero es congruente, vale con verificar unos pocos de los registros para calcular correctamente el tipo de valor de cada atributo. Cambiamos esto también en el código original, recompilamos GeoTools y recompilamos de nuevo GeoWave. Los cambios en el código fuente los puede encontrar en github en mi fork de GeoTools.

Después de este inciso, volvamos ahora a la senda principal de la guía, estamos en que ya hemos cargado una capa con la herramienta "ingest" de GeoWave, y de que hemos incluido el plugin comentado anteriormente en una instancia de GeoServer ya en funcionamiento (Ver guía del desarrollador, simplemente se copia el componente "geowave-deploy-xxx-geoserver.jar" previamente compilado a la carpeta "..\WEB-INF\lib" de GeoServer y reiniciamos).


GeoServer

GeoServer es un servidor de mapas open source que permite a los usuarios compartir y editar información geoespacial usando estándares abiertos. En efecto, implementa varios estándares definidos por el Open Geospatial Consortium (OGC), como por ejemplo el ampliamente utilizado Web Map Service (WMS). 


Nosotros utilizaremos GeoServer para consumir las capas cargadas con GeoWave, el plugin que acabamos de añadir a nuestra distribución nos permitirá conectarnos a estos datos, y así podremos usarlos como cualquier otra capa. Insisto Guau! :-)

Para configurar el acceso a las capas (Data Stores y Layers en términos técnicos), podemos utilizar dos opciones:

  • Utilizando de forma usual el panel de administración de GeoServer:

  • Utilizando el comando "gs" de GeoWave para registrar las capas en un GeoServer en funcionamiento.


Ya que estamos probando cosas, vamos con esta segunda opción. Un primero paso es indicar a GeoWave la instancia de GeoServer que queremos configurar.

> %geowave% config geoserver -ws geowave 
  -u admin -p geoserver http://localhost:8080/geoserver

De forma similar a lo que haríamos con el administrador de GeoServer, ejecutamos dos comandos para añadir respectivamente el "Data Store" y el "Layer" deseados.

> %geowave% gs addds -ds geowave_eea -ws geowave eea-store
> %geowave% gs addfl -ds geowave_eea -ws geowave NO2-measures



Como se observará, el sistema de referencia de la capa es el EPSG:4326, el resto de configuraciones las veremos como cualquier otra fuente de datos. Si previsualizamos los datos en el cliente OpenLayers que viene con GeoServer...



El rendimiento es bastante digno (Puede ver el vídeo vinculado a la imagen), teniendo en cuenta que estamos corriendo en un Portátil "normalito", con Hadoop en modo "nodo simple", y visualizando las observaciones de NO2 de todas las fechas posibles (~5.000.000 de registros). El filtro espacial trabaja perfectamente, a zoom más cercano, más rápida la respuesta. Si hacemos un filtro WFS usando el atributo de tipo fecha, comprobaremos también que el filtro temporal funciona, no se hace un escaneo por fuerza bruta de todos los datos.

En la guía de usuario de GeoWave se instruye para añadir a la capa un estilo especial llamado "subsamplepoints" (Usa internamente un WPS llamado "geowave:Subsample" que se implementa en el plugin de GeoWave). Lo que hace ese estilo es descartar en el pintado del mapa aquellas geometrías coincidentes a nivel de pixel, éstas no aportan nada en la imagen resultante. He de decir que se nota bastante la mejora de rendimiento, así que para pintar puntos recomiendo investigarlo.

He probado también a cargar una capa de recintos desde un Shapefile, cero problemas, funcionan las peticiones WMS GetMap y WFS GetFeature. Sólo un detalle, la carga con GeoWave automáticamente transforma las geometrías del sistema de referencia espacial original (EPSG:25830 fue mi caso) al comentado EPSG:4326 en coordenadas geográficas.



Bien, llegados a este punto hemos comprobado que todo encaja, podríamos parar aquí ya que la explotación de estos datos ya se podría realizar con herramientas Web Mapping (Leaflet, OpenLayers, AGOL, ...) o GIS desktop (QGIS, gvSIG, ...) estándar.

¿Seguimos?


Visor Web Mapping con Leaflet

Yo he seguido estrujando un poco más la prueba, he desarrollado un visor Web Mapping usando como base Leaflet. Este visor tiene la opción de ver los puntos de la capa en modo "Heatmap" o modo "rampa temática de color"; para ver los valores de una determinada fecha, y la simulación temporal de entre todas las fechas existentes.


Con esta prueba verificaremos además el rendimiento para peticiones que utilicen conjuntamente filtros espaciales y temporales. Vamos con ello.

Lo más fácil, y tal vez óptimo, hubiera sido realizar en el cliente WEB peticiones WMS tipo GetMap, pero lo que vamos a ejecutar son peticiones a GeoServer que recuperen las geometrías/puntos para pintarlos en cliente en la forma y tecnología que queramos. Podríamos usar una petición WFS tipo GetFeature con el BBOX actual de la vista y un filtro alfanumérico de una determinada fecha, pero no perdamos de vista que estamos usando una capa "Big Data" que nos puede devolver un GML o JSON de respuesta con miles y miles de registros.

Ya podéis esperar que habrá un momento en que el fichero de geometrías que debe procesar la aplicación cliente puede ser prohibitivo. Para evitar esto he desarrollado un par de módulos WPS para GeoServer llamados "geowave:PackageFeatureLayer" y "geowave:PackageFeatureCollection" que empaquetan el resultado de esa misma petición en un array de bytes comprimido. Se podría devolver el resultado con otro formato compacto, por ejemplo una imagen especial que codifique en los pixeles las geometrías. Todo sea por minimizar el tamaño de la información y acelerar la digestión de ella en la aplicación cliente.



En la imagen podemos ver que los parámetros de entrada del módulo son el nombre de la capa (Para el módulo "geowave:PackageFeatureCollection" es un objeto "SimpleFeatureCollection"), el BBOX que actúa de filtro espacial, y el filtro CQL a aplicar de forma opcional (En nuestro caso podría ser algo del estilo "datetime_begin = 2017-06-01 12:00:00").

No voy a describir en detalle el código del cliente web, se sale del ámbito de esta guía. Si lo desea, puede estudiar el código que publico en github al final del artículo.

Lo que hace la aplicación es ejecutar en un WebWorker una petición WPS a nuestro GeoServer usando el módulo anterior. El WebWorker descomprime el stream de bytes, lo parsea para generar los objetos javascript y lo devuelve finalmente al hilo principal del explorador para que sean dibujados. El visor pinta ya estos objetos javascript usando la librería Heatmap.js para el modo de visualización "mapa de calor" o sobre un Canvas HTML5 para el de "rampa de color". Para este segundo modo, la aplicación genera al vuelo una textura para cada uno de los iconos con color de la rampa. Este truco permite dibujar miles de puntos en un tiempo record.

Si nuestro cliente requiere dibujar millones de puntos, podemos bucear con WebGL y la estupenda WebGL Heatmap o demos impresionantes como How I built a wind map with webgl.

El código fuente del visor WEB y del modulo WPS está aquí.

No hay comentarios:

Publicar un comentario