Qué es Hive (Hadoop) | Introducción e Instalación

Qué es Hive (Hadoop) | Introducción e Instalación

Introducción a Hive

 

qué es Hive


Apache Hive es un software que forma parte del ecosistema de Hadoop. Es utilizado para gestionar enormes datasets almacenados bajo el HDFS de Hadoop y realizar consultas (queries) sobre los mismos.

Para esto, Hive implementa una variante al SQL, llamada HQL (Hive QL). Esta variante no soporta la especificación SQL-92 completa, pero sí una gran parte. Realmente, cuando se ejecutan consultas HQL, Hive convierte la consulta HQL a un trabajo MapReduce que es ejecutado para obtener los datos. La finalidad de esto es permitir a usuarios que no cuenten con experiencia en programación de algoritmos MapReduce (que suelen ser bastante laboriosos), pero que sí cuenten con conocimientos de SQL, poder consultar datos.

Un punto a favor de Hive es que trabajar con este es similar a trabajar con bases de datos tradicionales. Desde Hive debemos estructurar los datos agrupándolos en tablas, con sus columnas y tipos de datos asociados. Pintar en estas tablas los datos, luego procesarlos y finalmente analizarlos. No obstante, no hay que olvidar que Hive no es un motor de bases de datos.

El inconveniente que presenta Hive es que, al necesitar procesar la consulta y traducirla a lenguaje Java para crear el MapReduce, la latencia de respuesta es alta. A su vez, como mencionamos, tampoco soporta todo el lenguaje SQL, transacciones ni índices.

Para poder empezar a trabajar con Hive debemos, primero que nada, instalarlo. En este post veremos como hacer esto, y en futuros post comenzaremos aprender sobre otros temas como lenguaje HQL, tipos de datos, funciones predefinidas (built-in) y definidas por el usuario (UDF), etc.

 

Instalación


Instalación Hadoop

Lo primero es tener instalado y corriendo Hadoop en nuestro equipo. Caso contrario, pueden seguir este otro tutorial donde explicar como hacer esto:

 

Instalación Hive

Hecho esto, debemos bajar el instalador de Hive desde su web. Una vez descargado, lo descomprimimos y movemos a la carpeta ‘/usr/local/hive/’:

sudo mv apache-hive-2.1.0-bin /usr/local/hive

Nos aseguramos que el owner de la carpeta y sus contenidos sea el usuario Hadoop:

hadoop@ubuntu:/usr/local$ ls -l /usr/local/hive/
total 140
drwxrwxr-x 3 hadoop mauricio  4096 Nov  5 00:34 bin
drwxrwxr-x 2 hadoop mauricio  4096 Nov  5 12:20 conf
-rw-r--r-- 1 hadoop root         0 Nov  4 23:52 derby.log
drwxrwxr-x 4 hadoop mauricio  4096 Oct 11 02:59 examples
drwxrwxr-x 7 hadoop mauricio  4096 Oct 11 02:59 hcatalog
drwxr-xr-x 3 hadoop root      4096 Nov  5 12:22 iotmp
drwxrwxr-x 2 hadoop mauricio  4096 Oct 11 02:59 jdbc
drwxrwxr-x 4 hadoop mauricio 12288 Nov  5 11:48 lib
-rw-r--r-- 1 hadoop mauricio 29003 Jun  3 07:43 LICENSE
-rw-r--r-- 1 hadoop mauricio   513 Jun  3 07:43 NOTICE
-rw-r--r-- 1 hadoop mauricio  4122 Jun  3 07:43 README.txt
-rw-r--r-- 1 hadoop mauricio 50294 Jun 16 20:43 RELEASE_NOTES.txt
drwxrwxr-x 4 hadoop mauricio  4096 Oct 11 02:59 scripts
drwxr-xr-x 3 hadoop root      4096 Nov  4 23:52 ${system:java.io.tmpdir}

o en caso contrario, cambiamos esto con:

sudo chown -R hadoop /usr/local/hive/

Finalmente, agregamos al archivo ~/.bashrc del usuarios Hadoop las siguientes variables de entorno:

# HIVE
export HIVE_HOME=/usr/local/hive
export PATH=$PATH:$HIVE_HOME/bin
export CLASSPATH=$CLASSPATH:/usr/local/Hadoop/lib/*:.
export CLASSPATH=$CLASSPATH:/usr/local/hive/lib/*:.

Recordar que cada vez que modificamos el archivos .bashrc debemos actualizar las variables de entorno del sistema con source ~/.bashrc.

Configuración

Ahora debemos configurar una base de datos que utilizará Hive para guardar sus metadatos. Por defecto se utilizar una llamada Derby, pero que solo es apto para entornos de testing. Nosotros instalaremos y configuraremos esta base en MySQL. Entonces, lo primero es instalar MySQL:

sudo apt-get install mysql-server libmysql-java

y creamos el siguiente enlace simbólico:

ln -s /usr/share/java/mysql-connector-java.jar $HIVE_HOME/lib/mysql-connector-java.jar

Ahora nos logueamos en MySQL y creamos una base de datos donde se almacenaran los metadatos que genere Hive. Luego de crear la base de datos, debemos rellenarla con el esquema que se correspondiente que se encuentra en ‘$HIVE_HOME/scripts/metastore/upgrade/mysql/’:

$ mysql -u root -p

mysql> CREATE DATABASE metastore;
mysql> USE metastore;
mysql> SOURCE /usr/local/hive/scripts/metastore/upgrade/mysql/hive-schema-0.14.0.mysql.sql;

y le creamos un usuarios a Hive para que pueda acceder a la base de datos:

mysql> CREATE USER 'hiveuser'@'%' IDENTIFIED BY 'hivepass'; 
mysql> GRANT all on *.* to 'hiveuser'@localhost identified by 'hivepass';
mysql> flush privileges;

Ahora debemos incluir en el archivo /usr/local/hive/conf/hive-site.xml las siguientes lineas que indican a Hive como conectarse con la base de datos:

 <property>
   <name>javax.jdo.option.ConnectionURL</name>
   <value>jdbc:mysql://localhost/metastore?createDatabaseIfNotExist=true</value>
   <description>metadata is stored in a MySQL server</description>
 </property>
 <property>
   <name>javax.jdo.option.ConnectionDriverName</name>
   <value>com.mysql.jdbc.Driver</value>
   <description>MySQL JDBC driver class</description>
 </property>
 <property>
   <name>javax.jdo.option.ConnectionUserName</name>
   <value>hiveuser</value>
   <description>user name for connecting to mysql server</description>
 </property>
 <property>
   <name>javax.jdo.option.ConnectionPassword</name>
   <value>hivepass</value>
   <description>password for connecting to mysql server</description>
 </property>

Y ya estamos listos. Con esto deberíamos poder iniciar iniciar Hive… bueno, casi. Cuando he intentado ingresar a Hive me ha salido un error de permisos de escritura que he solucionado (googleando) añadiendo las siguientes lineas al archivos mismo archivo:

<property>
  <name>hive.querylog.location</name>
  <value> /usr/local/hive/iotmp</value>
  <description>Location of Hive run time structured log file</description>
</property>
<property>
  <name>hive.exec.local.scratchdir</name>
  <value>/usr/local/hive/iotmp</value>
  <description>Local scratch space for Hive jobs</description>
</property>
<property>
  <name>hive.downloaded.resources.dir</name>
  <value>/usr/local/hive/iotmp</value>
  <description>Temporary local directory for added resources in the remote file system.</description>
</property>

 

Testing

Vamos a comprobar ahora que la instalación se haya realizado correctamente.

Primero revisamos si Hive responder. Para esto ingresamos hive –version:

$ hive --version
Hive 2.1.0
Subversion git://jcamachguezrMBP/Users/jcamachorodriguez/src/workspaces/hive/HIVE-release2/hive -r 9265bc24d75ac945bde9ce1a0999fddd8f2aae29
Compiled by jcamachorodriguez on Fri Jun 17 01:03:25 BST 2016
From source with checksum 1f896b8fae57fbd29b047d6d67b75f3c

y ahora creamos una base de datos (realmente no es una base de datos lo que estamos creando, pero la podemos tratar como tal):

$ hive

...

hive> create table mauricio_test(id int, name string);
OK
Time taken: 2.424 seconds

Vamos a ver que tenemos en la base de datos de MySQL que creamos previamente:

$ mysql -u root -p

mysql> use metastore;
mysql> select * from TBLS;
+--------+-------------+-------+------------------+--------+-----------+-------+---------------+---------------+--------------------+--------------------+----------------+
| TBL_ID | CREATE_TIME | DB_ID | LAST_ACCESS_TIME | OWNER  | RETENTION | SD_ID | TBL_NAME      | TBL_TYPE      | VIEW_EXPANDED_TEXT | VIEW_ORIGINAL_TEXT | LINK_TARGET_ID |
+--------+-------------+-------+------------------+--------+-----------+-------+---------------+---------------+--------------------+--------------------+----------------+
|      1 |  1478359381 |     1 |                0 | hadoop |         0 |     1 | hive          | MANAGED_TABLE | NULL               | NULL               |           NULL |
|      6 |  1478371335 |     1 |                0 | hadoop |         0 |     6 | mauricio_test | MANAGED_TABLE | NULL               | NULL               |           NULL |
+--------+-------------+-------+------------------+--------+-----------+-------+---------------+---------------+--------------------+--------------------+----------------+
2 rows in set (0.00 sec)

 

Listo! Ya tenemos preparado nuestro equipo para trabajar con Hadoop utilizando Hive.

 

Comentarios

Hive (Hadoop) | Funciones y Tipo de Datos

Hive (Hadoop) | Funciones y Tipo de Datos

Ahora que tenemos instalado Hive en nuestro equipo comenzaremos a aprender como utilizarlo. Dado que trabajar en Hive es similar a trabajar con bases de datos relacionales en cuento al lenguaje de consulta, en este post nos vamos a dedicar a hablar de los tipos de datos y de las funciones predefinidas (Built-in), y en una segunda parte del post hablaremos sobre las funciones definidas por los usuarios (UDF, user defined function) y haremos algunos ejemplos de como trabajar con el HQL y manipular información.

 

qué es Hive

 

Tipos de datos


Los tipos de datos en Hive son clasificados en dos tipos: primitivos y complejos.

Los tipos de datos primitivos incluyen a los enteros (integer), booleanos (boolean), cadenas (string), etc.

Tipo
TINYINT      1 byte
SMALLINT     2 byte
INT          4 byte
BIGINT       8 byte
FLOAT        4 byte
DOUBLE       8 byte
BOOLEAN      TRUE/FALSE
STRING       tamaño máximo 2GB.
TIMESTAMP    almacenar fecha y hora
DATE         almacenar solo fecha

Mientra que los tipos complejos incluyen Arrays, Maps y Structs. Estos tipos de datos son construidos utilizando datos primitivos.

  • Arrays: Contienen una lista de elementos del mismo tipo. Estos elementos son accedidos por un índice. Por ejemplo, si el campo Mascota contiene a lista de elementos [‘perro’, ’gato’, ‘loro’], el elemento ‘gato’ puede ser accedido mediante Mascota[1].
  • Maps: Contienen pares clave-valor. Cada elemento es accedido mediante su clave. Por ejemplo, un map lista_passwords conteniendo “Mauricio” como clave y “passDeMauricio” como valor, el password del usuario es accedido mediante lista_passwords[‘Mauricio’].
  • Structs: Contienen elementos de diferente tipos. Cada elementos puede ser accedido mediante la notación punto (dot notation). Por ejemplo, en una estructura auto, el color del auto puede ser recuperado mediante auto.color.

Ejemplo:

CREATE TABLE complex_data_types
(
  mascota         ARRAY<string>,
  list_passwords  MAP<string,string>,
  auto            STRUCT<color:string, rodado:float>
);

Funciones predefinidas (built-in functions)


Las funciones predefinidas en Hive se clasifican en:

  • Funciones matemáticas y numéricas: principalmente utilizadas para realizar cálculos matemáticos.
  • Funciones de fecha: principalmente utilizadas para realizar operaciones sobre campos tipo fecha (date).
  • Funciones de cadena: usadas para realizar operaciones sobre cadenas (string).
  • Funciones condicionales: usadas para comprobar condiciones, en donde se devuelva una valor Verdadera o False según se cumpla o no la condición.
  • Funciones de acumulación: usadas para encontrar el tamaño de un campo complejo como un array o un map. La única función de este tipo es SIZE, la cual encuentra el número de elementos en uno de estos tipos. La sintaxis de esta función es:
SIZE(Array<A>)
SIZE(MAP<key,value>)
  • Funciones de conversión: usada para convertir un dato de un tipo a otro. La única función de esto tipo es CAST. La sintaxis de esta función es:
CAST(expr as <type>)
  • Funciones generadoras: estas funciones transforman un campo tipo array en múltiples campos. La única función de este tipo es EXPLODE, la cual toma un campo tipo array como entrada, y como salida devuelve los elementos del array en filas separados. Cuando se usa esta función en el SELECT, no se puede especificar ninguna otra columna. La sintaxis de esta función es:
EXPLODE(ARRAY<A>)

 

Funciones matemáticas y numéricas


 

ABS( double n ): valor absoluto de un número.

ABS(-1)

 

ACOS( double n ): arco-coseno de n. En caso de que n no esté en el intervalo [-1; +1] devuelve NULL.

ACOS(0.8)

 

ASIN( double n ): arco-seno de n. En caso de que n no esté en el intervalo [-1; +1] devuelve NULL.

ASIN(0.2)

 

BIN( bigint n ): convierte n a formato binario.

BIN(25)

 

CEIL( double n ), CEILING( double n ): redondea el valora decimal n al entero más cercano más pequeño.

CEIL(5.25)

 

CONV( bigint n, int from_base, int to_base ): convierte un número de una base a otra.

CONV(100, 10,2)

 

COS( double n ): devuelve el coseno de n, el cual debe estar indicado en radianes.

COS(3.14)

 

EXP( double n ): devuelve e^n.

EXP(5)

 

FLOOR( double n ): devuelve el entero superior más cercano a n.

FLOOR(10.9)

 

HEX( bigint n ): convierte el valor n a hexadecimal.

HEX(17)

 

HEX( string n ): convierte cada caracter en su representación hexadecimal.

HEX(‘ABC’)

 

LN( double n ): devuelve al logaritmo natural de n

LN(1.45)

 

LOG( double b, double n ): devuelve el logaritmo en base b de n.

LOG(3, 66)

 

LOG2( double n ): devuelve el logaritmo en base 2 de n.

LOG2(44)

 

LOG10( double n ): devuelve el logaritmo en base 10 de n.

LOG10(1000)

 

NEGATIVE( int n ),  NEGATIVE( double n ): devuelve el valor negativo de n.

NEGATIVE(10)

 

PMOD( int m, int n ), PMOD( double m, double n ): devuelve el módulo de la división entre m y n.

PMOD(3,2)

 

POSITIVE( int n ), POSITIVE( double n ): devuelve el valor positivo de n.

POSITIVE(-10)

 

POW( double m, double n ), POWER( double m, double n ): devuelve m^n.

POW(10,2)

 

RAND( [int seed] ): devuelve un número aleatorio.

RAND()

 

ROUND( double m[, int n] ): devuelve m redondeado con n decimales.

ROUND(1.456,2)

 

SIN( double n ): seno de n, el cual debe estar indicado en radianes.

SIN(2)

 

SQRT( double n ): raíz cuadrada de n.

SQRT(4)

 

UNHEX( string n ): inversa de la función HEX. Convierte la cadena dada a su formato numérico.

UNHEX(‘AB’)

 

 

Funciones de fecha


 

UNIX_TIMESTAMP(): devuelve la fecha y hora en formato UNIX epoch (número de segundos desde 1970-01-01 00:00:00 UTC).

UNIX_TIMESTAMP() -- returns 1476135611

 

UNIX_TIMESTAMP( string fecha): convierte la fecha en formato ‘yyyy-MM-dd HH:mm:ss’ a formato UNIX epoch, esto es, el número de segundo transcurridos desde 1970-01-01 00:00:00 UTC.

UNIX_TIMESTAMP('2000-01-01 00:00:00') -- returns 946713600

 

UNIX_TIMESTAMP( string fecha, string pattern ): convierte la fecha al formato indicado, y la devuelve esta en formato UNIX epoch.

UNIX_TIMESTAMP('2000-01-01 10:20:30','yyyy-MM-dd') -- returns 946713600

 

FROM_UNIXTIME( bigint number_of_seconds  [, string format] ): convierte la fecha en formato UNIX epoch al formato indicado. Por defecto ‘yyyy-MM-dd HH:mm:ss’.

FROM_UNIXTIME( UNIX_TIMESTAMP() )  -- returns the current date including the time

 

TO_DATE( string timestamp ): devuelve la fecha en formato ‘yyyy-MM-dd’.

TO_DATE('2000-01-01 10:20:30') -- returns '2000-01-01'

 

YEAR( string fecha ): devuelve el año.

YEAR('2000-01-01 10:20:30') -- returns 2000

 

MONTH( string fecha ): devuelve el mes.

MONTH('2000-03-01 10:20:30') -- returns 3

 

DAY( string fecha ), DAYOFMONTH( string fecha): devuelve el día.

DAY('2000-03-01 10:20:30') -- returns 1

 

HOUR( string fecha ): devuelve la hora.

HOUR('2000-03-01 10:20:30') -- returns 10

 

MINUTE( string fecha ): devuelve los minutos.

MINUTE('2000-03-01 10:20:30') -- returns 20

 

SECOND( string fecha ): devuelve los segundos.

SECOND('2000-03-01 10:20:30') -- returns 30

 

WEEKOFYEAR( string fecha ): devuelve el número de semana del año.

WEEKOFYEAR('2000-03-01 10:20:30') -- returns 9

 

DATEDIFF( string fecha1, string fecha2 ): devuelve el número de días entre las dos fechas.

DATEDIFF('2000-03-01', '2000-01-10') -- returns 51

 

DATE_ADD( string fecha, int dias ): suma a la fecha la cantidad indicada de días indicados.

DATE_ADD('2000-03-01', 5) -- returns '2000-03-06'

 

DATE_SUB( string fecha, int dias ): resta de la fecha la cantidad indicada de días indicados.

DATE_SUB('2000-03-01', 5) -- returns ‘2000-02-25’

 

 

Funciones de cadena


 

ASCII( string str ): convierte el primer caracter de la cadena en su valor numérico ASCII.

ASCII('hadoop') -- returns 104

ASCII('A')      -- returns 65

 

CONCAT( string str1, string str2, ... ): concatena todas las cadenas que se pasan como argumento.

CONCAT('hadoop','-','hive') -- returns 'hadoop-hive'

 

CONCAT_WS( string delimiter, string str1, string str2, … ): similar a CONCAT, pero entre las cadenas a concatenar se puede especificar el caracter que las delimitará.

CONCAT_WS('-','hadoop','hive') -- returns 'hadoop-hive'

 

FIND_IN_SET( string cadena_buscar, string lista_de_cadenas): busca la cadena cadena_buscar en lista_de_cadenas, y devuelve la posición de la primer ocurrencia. lista_de_cadenas debe estar formadas por cadenas separadas por coma.

FIND_IN_SET('ha','hao,mn,hc,ha,hef') -- returns 4

 

LENGTH( string str ): devuelve el número de caracteres de la cadena.

LENGTH('hive') -- returns 4

 

LOWER( string str ),  LCASE( string str ): convierte los caracteres de la cadena a minúsculas.

LOWER('HiVe') -- returns 'hive'

 

LPAD( string str, int n, string pad ): devuelve una cadena de n elementos, completando a la izquierda con el elementos pad hasta alcanzar la longitud indicada.

LPAD('hive',6,'v') -- returns 'vvhive'

 

LTRIM( string str ): elimina los espacios en blanco a la izquierda de la cadena.

LTRIM('   hive') -- returns 'hive'

 

REPEAT( string str, int n ): repite la cadena n veces.

REPEAT('hive',2) -- returns 'hivehive'

 

RPAD( string str, int n, string pad ): igual a LPAD, pero completando los caracteres a la derecha.

RPAD('hive',6,'v') -- returns 'hivevv'

 

REVERSE( string str ): invierte la cadena.

REVERSE('hive') -- returns 'evih'

 

RTRIM( string str ): elimina los espacios en blanco a la derecha de la cadena.

LTRIM('hive   ') -- returns 'hive'

 

SPACE( int n ): devuelve una cadena formada por n espacios en blanco.

SPACE(4) -- returns '    '

 

SPLIT( string str, string pat ): divide la cadena según el elemento pat  y devuelve un array de cadenas. Se puede especificar una expresión regular como pat.

SPLIT('hive:hadoop',':') -- returns ["hive","hadoop"]

 

SUBSTR( string str, int primer_elemento  [,int n]  ),  SUBSTRING( string str, int primer_elemento [,int n]  ): devuelve una parte de la cadena, desde primer_elemento hasta n elementos a la derecha. Si no se indica la cantidad de caracteres a tomar, se toman todos los caracteres hasta el final de la cadena.

SUBSTR('hadoop',4) -- returns 'oop'

SUBSTR('hadoop',4,2) -- returns 'oo'

 

TRIM( string str ): elimina los espacios en blanco tanto a derecha como a izquierda de la cadena.

TRIM('   hive   ') -- returns 'hive'

 

UPPER( string str ), UCASE( string str ): convierte los caracteres de la cadena a mayúscula.

UPPER('HiVe') -- returns 'HIVE'

 

 

Funciones condicionales


 

IF( condición,  bloque verdadero, bloque falso ): la sentencia IF evalúa la condición, si es verdadera devuelve el valor de bloque verdadero, caso contrario, devuelve el valor de bloque falso.

IF(1=1, 'working', 'not working') -- returns 'working'

 

COALESCE( valor1, valor2,… ): devuelve el primer valor no NULL de la lista de valores. Si todos los elementos de la lista son NULL, devuelve NULL.

COALESCE(NULL,NULL,5,NULL,4) -- returns 5

 

CASE:

CASE [ expresión ]

     WHEN condición1 THEN resultado1

     WHEN condición2 THEN resultado2

     ...

     WHEN condición_n THEN resultado_n

     ELSE resultado

END

El valor expresión es opcional y, de estar presente, se comparará en la lista de elementos condición (condición1, condición2, …, condición_n). Todos los elementos en la lista de condiciones deben ser del mismo tipo. Las condiciones serán evaluadas en el orden dado. Una vez que una condición es hallada verdadera, se ejecuta el resultado asociado a esta, y luego se sale del bloque CASE. A su vez, todos los elementos resultado deben ser del mismo tipo. En caso de que ninguna condición sea verdadera se ejecuta el bloque ELSE, el cual es opcional. Si este no se encuentra, y ninguna condición resulta verdadera, se devuelve NULL.

Ejemplo:

CASE Fruta
     WHEN 'MANZANA' THEN 'ES UNA MANZANA'
     WHEN 'NARANJA' THEN 'ES UNA NARANJA'
     ELSE 'ES OTRA FRUTA'
END

o

CASE
     WHEN Fruta = 'MANZANA' THEN 'ES UNA MANZANA'
     WHEN Fruta = 'NARANJA' THEN 'ES UNA NARANJA'
     ELSE 'ES OTRA FRUTA'
END

 

Comentarios