lunes, 22 de junio de 2015

Ejemplo Map Reduce

Vamos a ver el proceso necesario para crear un job de map reduce en hadoop.

Son dos los jars necesarios que importaremos en nuestro proyecto de eclipse y que se pueden descargar de :

common
mapreduce-client-core

Para implementar un Map Reduce se deben crear tres clases :

Map


public static class ExampleMapper extends Mapper



Ha de extender de la clase Mapper de hadoop y tendremos que sobreescribir el metodo map, que tiene como atributos key, value y context



public void map(Object key, Text value, Context context) throws IOException, InterruptedException {



Aquí se reciben los bloques de datos de información y la deberemos tratar linía a linía, para ello definiremos el comportamiento deseado de nuestro algoritmo y tambien determinaremos los valores de entrada ( key: un apuntador hacía nuestro fichero | value: cada una de las linias) y el formato de salida que se convertirá en la entrada del Reduce (context), por ejemplo :



context.write(new Text(valorTratado1), new DoubleWritable(Double.parseDouble(valorTratado2)));




Reduce



public static class ExampleReducer extends Reducer{



Al igual que en el caso de map, reduce debe sobreescibir el método reduce :



public void reduce(Text key, Iterable values, Context context) throws IOException, InterruptedException {



Dónde key sera valorTratado1 y values sera un Iterador del tipo de objecto que hayamos definido en el context de map (en nuestro caso DoubleWritable) que tendrá un array con todos aquellos valores que tengan la misma key

Aquí se recogen los datos agrupados por clave que nos envia la clase map definida anteriormente y se tratan de la manera deseada. Una vez realizado este tratamiento se prepara la salida mediante el objeto context  :



context.write(key, new Text(valorTratado3));




Veamos unas imágenes del proceso de map reduce para un algoritmo WordCount ( el "hello world" de hadoop) :







Driver


La clase driver es la encargada de ejecutar y configurar el Job de Map Reduce que hayamos creado. Para ello crearemos la clase y extenderemos de , lo que nos obligara a sobreescribir el método run dónde crearemos y configuraremos el job a ejectuar :


public class ExampleDriver extends Configured implements Tool{

@Override
public int run(String[] arg0) throws Exception {
// TODO Auto-generated method stub
return 0;
}
}


Aquí definiremos todo lo relacionado a nuestra ejecución o job, para ello crearemos un nuevo job:



final Job job = Job.getInstance(getConf(), "NombreDelJob");

job.setJarByClass(ExampleDriver.class);


//Archivo de entrada HDFS
        job.setInputFormatClass(TextInputFormat.class);

//Archivo de salida HDFS
        job.setOutputFormatClass(TextOutputFormat.class);


//Definimos clase Map
        job.setMapperClass(ExampleMapper.class);
//Definimos clase Redice

        job.setReducerClass(ExampleReducer.class);
 //Sortida del map, definim tipus parametre
        job.setMapOutputKeyClass(Text.class);
        job.setMapOutputValueClass(DoubleWritable.class);
//Sortida Reduce, definim tipus parametre
        job.setOutputKeyClass(Text.class);

        job.setOutputValueClass(Text.class);

//Definimos los paths de entrada y salida segun los parametros recogidos por linia de comandos
        FileInputFormat.addInputPath(job, new Path(args[0]));
        FileOutputFormat.setOutputPath(job, new Path(args[1]));


        job.waitForCompletion(true);

        return 0;


Es una buena práctica crear un método que borre el direcotrio de destino de los datos y ejecutarlo antes de crear la instancia de job ya que hadoop falla si ya existe esa carpeta y tiene contenido :


private void deleteOutputFileIfExists(String path) throws IOException {
       final Path output = new Path(path);
       FileSystem.get(output.toUri(), getConf()).delete(output, true);
}



Luego crearemos el punto de entrada con un método main donde, mediante el ToolRunner crearemos una instancia de nuestra clase ExampleDriver pasandole los argumentos que hayamos recogido des de la linia de comandos :



 public static void main(String[] args) throws Exception {
       ToolRunner.run(new ExampleDriver(), args);
}



Para realizar la ejecución del jar de Map reduce creado ejecutaremos :


hadoop jar MapReduceEx1.jar com.mapreduceex1.ExampleDriver /user/add/archivo.csv /user/add/salida

Donde /user/add/calidad.csv será la ruta de nuestro hdfs (en hadoop) previamente importado y
 /user/add/salida será el directorio donde se dejará el resultado (en hadoop)

Estos dos parámetros los hemos configurado por código

miércoles, 13 de mayo de 2015

Actualizar los datos de una tabla en Hive con Sqoop

Una vez realizado el import de la tabla en HDFS y la posterior creación de la misma en Hive, podemos necesitar realizar una acualización de los datos que se han generado desde el momento de nuestra creación hasta ahora, para ello utilizaremos el comando (caso sqlserver):


sqoop import --connect "jdbc:sqlserver://:1433;database=;username=;password=" --table --hive-import --check-column --incremental append --last-value

Un dato interesante es que la importación de una tabla en una BD relacional con sqoop hacia un HDFS se traduce en que el fichero HDFS contiene los datos separados por comas, muy similar al formato de un CSV.

Si vemos que los datos se han actualizado en hive pero no en impala, refrescamos la tabla con la instrucción: REFRESH

lunes, 11 de mayo de 2015

Json Java

En esta entrada voy a describir como crear un json en la parte servidor y devolvérselo al cliente.

Noves Investigacions

Recientemente he dado una charla sobre un tema que estoy investigando para el trabajo final del Máster de Software Libre.

Concretamente el titulo de la conferéncia ha sido :

Detecció de plagi en la creació de circuits digitals en entorn educatiu, desenvolupament d'una eina de Software Lliure

Importar datos con Sqoop desde una Base de Datos Relacional

En primer lugar deberemos bajar el driver necesario para conectarnos a la base de datos 



MySQL JDBC Driver



Oracle JDBC Driver



Microsoft SQL Server JDBC Driver


curl -L 'http://download.microsoft.com/download/0/2/A/02AAE597-3865-456C-AE7F-613F99F850A8/sqljdbc_4.0.2206.100_enu.tar.gz' | tar xz

PostgreSQL JDBC Driver


curl -L 'http://jdbc.postgresql.org/download/postgresql-9.2-1002.jdbc4.jar' -o postgresql-9.2-1002.jdbc4.jar


Luego copiaremos el jar que se encuentra en sqljdbc_4.0/enu/sqljdbc4.jar en /var/lib/sqoop ( puede requerir un reinicio)

Con esto ya podremos realizar la conexión

Para comprobar si funciona listaremos las bases de datos ( en el caso de sqlserver, en el resto de la misma manera cambiando la información del conector ):

sqoop list-databases --connect jdbc:sqlserver://: --username   --password 


Para realizar la importación a Hdfs :

sqoop import --connect "jdbc:sqlserver://:;database=;username=;password=" --table  


Para realizar la importación a Hive directamente


sqoop import --connect "jdbc:sqlserver://;database=;username=;password=" --table  --hive-import

Si queremos realizar una importación de todas las tablas que contiene una base de datos, podemos hacer :

sqoop import-all-tables --connect "jdbc:sqlserver://ip:puerto;databalse=nombreDB;username=user;password=pass"

Si alguna de las tablas no tiene primaryKey tenemos dos opciones, definir por que campo diferenciaremos con -split-by o marcar que en vez de ejecutar los 4 maps que arranca por defecto sqoop, lo hagamos con un solo map con la instrucción -m 1, de esta manera no será necesario realizar los splits de la entrada del map y todo se tratara en el mismo map task.

También podemos excluir alguna de las tablas que queramos al hacer toda la importación mediante el argumento --exlclude-table nombretaba1,nombretabla2...

De esta manera la instrucción para importar todas las tablas de una bd a hive menos una, con alguna que no contenga primarykey, quedaría así :

sqoop import-all-tables --connect "jdbc:sqlserver://ip:puerto;databalse=nombreDB;username=user;password=pass" -m 1 --exclude-table nombretabla --hive-import


Los hdfs importados se guardarán en hive/warehouse y veremos que solo contienen un part-m-00000 correspondiente a cada una de las tablas que hemos importado

Para crear una tabla en hive igual que la que tenemos en la base de datos haremos :

sqoop create-hive-table --connect "jdbc:sqlserver://ip:puerto;databalse=nombreDB;username=user;password=pass" --table NombreDeLaTabla

La instrucción creará la estructura de la misma forma que en nuestra BD relacional pero no importara los datos que esta contenga.

Para cargar los datos des de un hdfs (que puede haber sido cargado previamente con sqoop en hdfs) a una tabla de hive haremos (previamente estaremos en el hive shell ) :

hive>LOAD DATA INPATH "nombredelHdfs" INTO TABLE nombreDeLaTabla

Si los datos a cargar están de manera local en nuestro filesystem, haremos :

hive>LOAD DATA LOCAL INPATH "nombredelarchivo" INTO TABLE nombreDeLaTabla

Veamos ahora un contenido un poco mas avanzado

Una alternativa si no queremos importar toda una tabla y queremos hacerlo a medida mediante una query propia pasa por introducir el parametro -query en la instrucción, en este caso también deberíamos introducir --split-by, veamos un ejemplo : 



sqoop import --connect "jdbc:sqlserver://192.168.7.128:1433;database=Selenium;username=sa;password=P@ssw0rd" --query 'SELECT Resultado.idResultado, Paso.idPaso, Resultado.Fecha, Resultado.TiempoPaso,Test.idTest, Resultado.idGrupTest, Browser.Nombre,Calendario.EveryXMinutes, Resultado.idError, Resultado.errorMsg from Resultado INNER JOIN Paso ON Resultado.idPaso = Paso.idPaso INNER JOIN Test ON Resultado.idTest = Test.idTest INNER JOIN Browser ON Test.Browser = Browser.id INNER JOIN TestCalendario ON Resultado.idTest = TestCalendario.idTest INNER JOIN Calendario ON TestCalendario.idCalendario = Calendario.idCalendario WHERE $CONDITIONS' --split-by Resultado.idTest --incremental append --check-column idResultado --target-dir /dfs/sqlData/Resultado

jueves, 7 de mayo de 2015

Importar csv a Hive.

Vamos a seguir el proceso para importar un fichero csv a hive. Como requisito necesitaremos tener instalado Cloudera 5 (ver post anterior)

martes, 5 de mayo de 2015

Instalación Cloudera 5 en Ubuntu 14.04 min

Si has llegado hasta aquí sabrás que es Hadoop y por lo tanto estarás familiarizado con el concepto de Big Data, en este post voy a seguir paso a paso el proceso de instalación de la plataforma Cloudera sobre una máquina virtual en VMWare con so Ubuntu 14.04 min de una manera lo mas sencilla posible. No pretende ser la forma mas canónica de hacerlo, pero pretende ser una manera simple para llegar al final del proceso con éxito.

lunes, 27 de abril de 2015

Inserts con clave primaria autoincremental en Hibernate y SQL Server

Algunas veces me he encontrado que teniendo que realizar un insert autoincremental en una Base de Datos SQL Server, el típico session.save(Object) ha fallado y no sabemos porque. Para eso utilizo el siguiente método como alternativa para realizarlos, 

jueves, 26 de marzo de 2015

Swipe para refrescar una Lista en Android

En la siguiente entrada voy a describir el proceso para crear un evento en el cual, mediante un deslizamiento del dedo hacia abajo se va a actualizar una lista.

jueves, 12 de marzo de 2015

Pequeño proyecto con Arduino

En esta entrada voy a presentar un pequeño proyecto hecho con Arduino.

Básicamente se trata de un desarrollo muy sencillo formado por un módulo compuesto por dos motores y un detector de distancia. 

viernes, 26 de septiembre de 2014

Manejo de fechas Java

Un poco sobre el manejo de fechas en Java de una manera muy práctica :

martes, 23 de septiembre de 2014

Algunos comandos interesantes

Esta entrada deriva de una práctica del Máster de Software Libre de la UOC de la asignatura Administración de sistemas Linux. 

En ella voy a escribir algunos comandos de linux que aparecían en esta práctica, no pretenden ser la manera mas sencilla de hacer las cosas, simplemente los menciono porque algunos de ellos me parecen interesantes.