A blog about data, information and Tech by Mario Alberich

        

#MapReduce: probar en #linux antes de ejecutar en #Hadoop

Diez años de MapReduce


En Diciembre se cumplirán diez años desde que Google publicó el paper sobre MapReduce. El objetivo de ese artículo era exponer un algoritmo para procesar paralelamente grandes cantidades de datos utilizando una infraestructura basada en equipos informáticos modestos, y que por ello fuera más fácilmente escalable.</p>

Diez años más tarde MapReduce se encuentra en el núcleo del BigData, especialmente a través de Hadoop.  Todas o casi todas las grandes compañías que ofertan bigdata ofrecen algún tipo de implementación de Hadoop a sus clientes.

Pero Hadoop es una implementación que no sólo incluye un algoritmo, sino también un sistema de archivos (Hadoop Filesystem, HDFS, basado a su vez en el Google File System, GFS) y todos los mecanismos de control necesario para llevar a cabo el tratamiento de datos a gran escala.

Entonces, si lo que queremos es entender el cambio de paradigma que supone MapReduce para tratar datos, ¿Necesitamos instalar Hadoop o un similar para entender el funcionamiento de MapReduce? Si lo que quieres probar son tus scripts con un pequeño conjunto de datos, no.

Consola y pipes


MapReduce tiene como base de funcionamiento el traspaso de información entre los procesos mediante pipes, lo que permite evitar el almacenamiento de datos en la memoria del proceso. Por ello, los scripts deben basarse en capturar la información del STDIN, y retornar la información a través del STDOUT. Si por ejemplo los datos están en un archivo CSV, podemos volcar el contenido con el comando cat (o head, o tail para sólo enviar un subconjunto de datos), enviándolo con un pipe a nuestro script de mapeo:

cat archivo.csv | ./mapper.php

Entonces, el script mapper.php debería abrir el flujo de datos recibidos a través de STDIN para empezar a procesarlo:

#!/usr/bin/php
$stdin = fopen( 'php://stdin', 'r' );

while( $line = fgetcsv( $stdin, 10000) ) {
// Procesar/mapear los datos y ejecutar un echo sprintf:
echo sprintf("%s\n", $line[0]);
}
?>


No añado ningún tipo de control en el script anterior, para ponerlo lo más simple posible. El script anterior imprime el contenido de la primera columna del archivo CSV.

En el caso del script de reducer (reducer.php), lo que haremos es contar cuántas veces aparece cada cadena en el listado (es decir que ignoraremos el valor numérico).  El script es bastante similar al del mapper, pero ahora mantendremos un contador de las veces que aparece la clave, y cuando ésta cambie, la imprimiremos:

#!/usr/bin/php
$stdin = fopen( 'php://stdin', 'r' );
$currentKey = null;
$currentCount = 0;
while( $line = fgets( $stdin ) ) {
// Generas el proceso de 'reducción'
if ($line !== $currentKey) {
echo sprintf("%s\t%s\n", $currentKey, $currentCount);
$currentKey = $fields[0];
$currentCount = 0;
}
$currentCount++;
}
if ($currentKey !== null) {
echo sprintf("%s\t%s", $currentKey, $currentCount);
}
?>

Vale, entonces ya tienes mapper.php y reducer.php. Para simplificar mucho, sólo queda un paso intermedio entre el mapper y el reducer: la ordenación de los registros recibidos (la parte Sort de lo que se denomina el Shuffle and Sort del algoritmo). Para que el reducer pueda calcular las veces que aparece cada clave, debe recibir los datos ordenados según esta clave. Para el caso que nos ocupa, lo podemos conseguir con el comando sort de Linux, no hace falta que nos compliquemos más.

Ejecutando el proceso conjunto


Un paso más antes de probar: para poder ejecutar los dos scripts php desde la línea de comandos es necesario marcarlos como ejecutables:

chmod +x mapper.php reducer.php

Todo a punto.  Poniéndolo todo en orden, tenemos que el comando sería:

cat archivo.csv | ./mapper.php | sort | ./reducer.php

Y, reducer.php debería generar una salida con los datos procesados (en este caso, un contador de la frecuencia de cada clave). Así que a grandes rasgos, esto es lo que plantea MapReduce: un algoritmo que pueda recibir una entrada de datos y que pueda procesarla, de forma independiente al resto del dataset.

El resto de la implementación de MapReduce (replicación de datos, gestión de recursos, partición del dataset, etc.) es imprescindible para operar con un gran conjunto de datos, pero no para entender el concepto de base: procesar datos de forma paralela.

Nota final: Aunque Hadoop requiere el uso de Java para desarrollar trabajos MapReduce, incorpora también una funcionalidad llamada Hadoop Streaming que permite la ejecución de scripts MapReduce en prácticamente cualquier lenguaje de programación. La contrapartida es un mayor uso de recursos y mayor lentitud, pero desde luego ayuda a realizar pruebas sencillas con scripts de PHP, python o similares.

© 2007 and beyond Mario Alberich, licensed under CC-BY-SA unless stated otherwise.