Desarrollo de aplicaciones
con Hadoop
Tomas Delvechio
@tdelvechio
tomasdelvechio17@gmail.com
El objetivo es poder realizar una instalación local y desarrollar algunas aplicaciones MapReduce, haciendo un uso simple del Sistema de Archivos Distribuido que proporciona Hadoop.
Instalar Hadoop implica instalar sus 3 componentes principales:
En todos los nodos. La diferencia entre nodo master y nodo slave se establece en la configuración e inicialización de los servicios
Sistema Operativo Linux
No hay procesamiento distribuido
Instalación para desarrollo
Linux: Ubuntu 14.04
Hadoop 2.7 / Hadoop 2.4 / Hadoop 2.5
OpenJDK 6 / 7
https://docs.docker.com/engine/installation/
Comprobar si el cliente esta instalado:
$ docker --version Docker version 1.12.1
2. Descargar imagen
$ docker pull sequenceiq/hadoop-docker:2.7.1
3. Iniciar Contenedor
docker run -it sequenceiq/hadoop-docker:2.7.1 /etc/bootstrap.sh -bash
4. Ejecutar Test
(Dentro del contenedor)
cd $HADOOP_PREFIX
bin/hadoop jar \
> share/hadoop/mapreduce/hadoop-mapreduce-examples-2.7.1.jar \
> grep input output 'dfs[a-z.]+'
bin/hdfs dfs -cat output/*
mkdir ~/cursohadoop
docker run -v ~/cursohadoop:/cursohadoop \
-w /cursohadoop -it sequenceiq/hadoop-docker:2.7.1 \
/etc/bootstrap.sh -bash
Ejecución de contenedor para trabajar en el curso.
Agregar los ejecutables de hadoop al path del sistema
export PATH=$PATH:/usr/local/hadoop/bin
Desde el navegador web de nuestro equipo
ResourceManager: <ip_container>:8088
NameNode: <ip_container>:50070
Descarga de archivos de ejemplo: https://goo.gl/ngB0aP
hdfs dfs -ls /
hdfs dfs -mkdir /user/hduser
hdfs dfs -mkdir /user/hduser/test
hdfs dfs -ls /user/hduser/
$ ls
pg135.txt pg1661.txt pg4300.txt
$ hdfs dfs -copyFromLocal pg135.txt pg1661.txt pg4300.txt /user/hduser/test
$ hdfs dfs -ls /user/hduser/test/
Found 3 items
-rw-r--r-- 1 hduser supergroup 3322651 2014-09-08 13:21 /user/hduser/test/pg135.txt
-rw-r--r-- 1 hduser supergroup 594933 2014-09-08 13:21 /user/hduser/test/pg1661.txt
-rw-r--r-- 1 hduser supergroup 1573150 2014-09-08 13:21 /user/hduser/test/pg4300.txt
hdfs dfs -cat /user/hduser/test/pg1661.txt
hdfs dfs -copyToLocal /user/hduser/test/pg1661.txt pg1661_bis.txt
diff pg1661_bis.txt pg1661.txt
Aplicación MapReduce que computa la frecuencia de cada termino de la entrada
public static class Map extends Mapper<LongWritable, Text, Text, IntWritable> {
private final static IntWritable one = new IntWritable(1);
private Text word = new Text();
@Override
public void map(LongWritable key, Text value, Context context)
throws IOException, InterruptedException {
String line = value.toString();
StringTokenizer tokenizer = new StringTokenizer(line);
while (tokenizer.hasMoreTokens()) {
word.set(tokenizer.nextToken());
context.write(word, one);
}
}
}
public static class Reduce extends Reducer<Text, IntWritable, Text, IntWritable> {
@Override
public void reduce(Text key, Iterable<IntWritable> values, Context context)
throws IOException, InterruptedException {
int sum = 0;
for (IntWritable val : values) {
sum += val.get();
}
context.write(key, new IntWritable(sum));
}
}
public class WordCount {
public static void main(String[] args) throws Exception {
Configuration conf = new Configuration();
Job job = Job.getInstance(conf);
job.setJarByClass(WordCount.class);
job.setOutputKeyClass(Text.class);
job.setOutputValueClass(IntWritable.class);
job.setMapperClass(Map.class);
job.setReducerClass(Reduce.class);
job.setInputFormatClass(TextInputFormat.class);
job.setOutputFormatClass(TextOutputFormat.class);
FileInputFormat.addInputPath(job, new Path(args[0]));
FileOutputFormat.setOutputPath(job, new Path(args[1]));
job.waitForCompletion(true);
}
}
package wordCount;
import java.io.IOException;
import java.util.*;
import org.apache.hadoop.fs.Path;
import org.apache.hadoop.conf.*;
import org.apache.hadoop.io.*;
import org.apache.hadoop.mapreduce.*;
import org.apache.hadoop.mapreduce.lib.input.FileInputFormat;
import org.apache.hadoop.mapreduce.lib.input.TextInputFormat;
import org.apache.hadoop.mapreduce.lib.output.FileOutputFormat;
import org.apache.hadoop.mapreduce.lib.output.TextOutputFormat;
Ejecutar en Hadoop: hadoop jar wordcount.jar wordCount.WordCount /user/hduser/test/* /user/hduser/out-wc
Map / Reduce con otros lenguajes
Ejemplo: Contar la cantidad de palabras de un archivo
hadoop jar hadoop-streaming-2.7.1.jar \ -input /user/hduser/test/* \ -output /user/hduser/out-wc-sh \ -mapper /bin/cat \ -reducer /usr/bin/wc
La librería hadoop-streaming se puede localizar en el path
/usr/local/hadoop/share/hadoop/tools/lib/hadoop-streaming-2.7.1.jar
El flujo de datos es similar al visto para Hadoop
Sin embargo, Map y Reduce ejecutan los scripts que se pasan por parametro. El I/O se hace por Entrada y Salida Estandar.
Elija el lenguaje que crea conveniente (Python, Ruby, Perl, Bash), y porgráme un Mapper y un Reducer para que realicen un WordCount.
Recordar que el I/O del script Map y Reduce es via Entrada/Salida Estandar.
Por ejemplo, en python, un script que haga print "Hola mundo" imprime el string por la salida estandar.
Tomando el ejemplo de WordCount, piense alguna modificación para crear un programa que realice otra tarea.
Implementarlo en Hadoop
Ejemplos:
Contador de Bigramas
Indice Invertido Booleano
Ayuda: Muchas veces programas de estructura similar ofrecen respuestas diferente en función de las decisiones de que es clave o valor en map y reduce.