Desde hace ya unos cuantos años, los programadores nos hemos visto forzados a realizar implementaciones específicas para trabajar con grandes volúmenes de datos (el famoso Big Data) y extraer información relevante derivada de ellos. Aunque muchos de estos cálculos son directos, el tamaño de la información entrante suele ser grande y ésta debe distribuirse entre cientos o miles de máquinas para poder resolver nuestro problema en una cantidad razonable de tiempo. ¿Qué herramientas tenemos para poder abordar esto?.

Modelo de programación

MapReduce es un modelo de programación desarrollado por Google y constituye una propuesta que pretende resolver las dificultades anteriores, ya que sus características y motivación se basan en la delegación de los cómputos intensivos en datos a un clúster de máquinas remotas que, mediante un sistema de ficheros distribuido, repartirán la carga de trabajo, optimizando tiempo y recursos. Asimismo, facilita un patrón de desarrollo paralelo para simplificar la implementación de aplicaciones intensivas en datos en entornos distribuidos. En resumen, este modelo puede dividir un espacio grande de problema en espacios pequeños y paralelizar la ejecución de tareas más pequeñas en estos sub-espacios.

Este procesado computacional puede tener lugar tanto sobre datos almacenados en sistemas de ficheros, como en bases de datos. El modelo de programación está inspirado en los lenguajes funcionales y permite al desarrollador expresar sus algoritmos utilizando únicamente dos funciones, map y reduce (de ahí el nombre del modelo). Estas funciones se definen sobre datos estructurados en pares clave-valor.

  • La función map, escrita por el usuario, recibe un par clave-valor y devuelve un conjunto de pares clave-valor intermedio:
    map (k1, v1) –> list (k2, v2)
    Esta función se aplica en paralelo a cada par del conjunto de datos de entrada produciendo una lista de pares (k2, v2) por cada llamada. MapReduce agrupa todos los valores intermedios asociados con la misma clave k y se los pasa a la función reduce.
  • La función reduce recibe esa clave y su conjunto de valores asociados y los fusiona para formar un conjunto de valores posiblemente más pequeño:
    reduce (k2, list (v2)) -> list (v3)
    Cada llamada reduce produce típicamente bien un valor v3 o un valor vacío, aunque una misma llamada puede devolver más de un valor. Los resultados de las llamadas se recopilan en la lista de resultados buscada.

Para ilustrar en líneas generales el funcionamiento de este modelo de programación, tómese de ejemplo el problema de contar el número de ocurrencias de cada palabra en un conjunto de documentos. El usuario debería codificar un algoritmo similar al siguiente pseudo-código:

map(String key, String value):
//key: nombre del documento
//value: contenido del documento
for each word w in value:
EmitIntermediate(w, “1”);
reduce(String key, Iterator values):
//key: una palabra
//values: una lista de ocurrencias
int result = 0;
for each v in values:
result += ParseInt(v);
Emit(AsString(result));


En resumen, la función map emite cada palabra con un número de ocurrencias asociado (“1”, en este caso) y la función reduce suma estos valores y emite el número de ocurrencias totales de cada palabra en cuestión.

OK, ¿cómo implemento esto, entonces?.

Hadoop es una de las implementaciones de código abierto de MapReduce. Es un proyecto Apache basado en Java que soporta aplicaciones distribuidas con alta carga de datos (del orden de miles de nodos y petabytes de información). Ha sido desarrollado, empleado y mantenido por una comunidad extensa de usuarios, siendo Yahoo! el principal benefactor del proyecto -y uno de sus principales consumidores- ya que utiliza Hadoop extensivamente en sus búsquedas web y negocios de publicidad. Asimismo, IBM y Google utilizaron Hadoop como referencia en sus cursos de programación con computación distribuida.
La arquitectura de Hadoop se vertebra sobre tres pilares fundamentales:

  • Sistema de ficheros: Hadoop se apoya para su funcionamiento en un sistema de ficheros distribuido (HDFS)
  • Hadoop MapReduce: El motor de Hadoop consta de un planificador de trabajos MapReduce, así como de una serie de nodos encargados de llevarlos a cabo.
  • Hadoop Common: conjunto de utilidades que posibilitan la integración de subproyectos de Hadoop.

Uno de estos subproyectos que forman parte del ecosistema de Hadoop es el que introduciremos a continuación.

Pig es un subproyecto de Hadoop que ofrece un lenguaje de consultas de alto nivel (Pig Latin) y un framework de ejecución para computación paralela. Dicho lenguaje permite ejecutar una serie de funciones de transformación, agrupamiento o filtrado sobre los datos con el fin de optimizar los resultados obtenidos, así como combinar la declaración de consultas de alto nivel propia de SQL, con un modelo de programación del estilo MapReduce.

Las características generales de Pig se podrían resumir en las tres siguientes:

  • Facilidad de programación, ya que por medio de directivas de alto nivel se podrá trabajar con grandes conjuntos de datos, transformándolas en secuencias de información de alto nivel, fáciles de escribir, entender y mantener.
  • Optimización automática, ya que de la forma en que se codifica la información se permite que el sistema se optimice de forma automática, permitiendo al usuario centrarse en la semántica más que en la optimización.
  • Extensibilidad, ya que el usuario puede escribir sus propias funciones de tratamiento de datos (User-Defined Functions, UDFs).

Aplicación práctica de todo el rollo anterior

Allá por el 2009, cuando me tocó realizar el Proyecto de Fin de Carrera, le propuse a mi tutor que estaba interesado en hacer algo diferente y no caer en los tópicos de las tecnologías y tendencias del momento. Él me comentó que uno de los grandes problemas que se estaban encontrando en el ámbito académico era el de trabajar con grandes volúmenes de datos ya que, si no se saturaba el hardware, los resultados tardaban semanas en llegar.

De ahí que adaptando el modelo tradicional de AGPs (Algoritmos Genéticos Paralelos) al modelo de programación MapReduce y basándome en una implementación de código abierto de éste (Hadoop), estudié soluciones a varios problemas clásicos en Algoritmos Genéticos, intentando demostrar la versatilidad, convergencia y escalabilidad de esta aproximación. Para aquellos interesados, la memoria del mismo se encuentra aquí, el código fuente se puede descargar desde aquí y los vídeos utilizados en la demo el día de la defensa aquí.

Desde aquellas hasta hoy (2017), estas herramientas han madurado y su uso se ha popularizado y extendido ampliamente, siendo sus ámbitos principales:

  • Industria química/farmacéutica: Análisis de datos
  • Sistemas en tiempo real: Toma de decisiones
  • Indexadores de texto
  • Banca: control de fraudes, conocer mejor al cliente
  • Buscadores: Minería de datos

Deja un comentario

Este sitio usa Akismet para reducir el spam. Conoce cómo se procesan los datos de tus comentarios.