Carga de datos en distintos formatos#

  • Última modificación: Mayo 17, 2022 | YouTube

Hive permite la lectura de archivos en distintos formatos. Al finalizar este tutorial, el lector estará en capacidad de leer archivos en formatos de texto, CSV y JSON.

Cell magic %%hive#

[1]:
from IPython.core.magic import Magics, cell_magic, line_magic, magics_class
from pexpect import spawn

TIMEOUT = 60
PROG = "hive"
PROMPT = ["\r\n    > ", "\r\nhive> "]
QUIT = "quit;"


@magics_class
class Magic(Magics):
    def __init__(self, shell):
        super().__init__(shell)
        self.app = spawn(PROG, timeout=60)
        self.app.expect(PROMPT)

    @cell_magic
    def hive(self, line, cell):
        cell_lines = [cell_line.strip() for cell_line in cell.split("\n")]
        cell_lines = [cell_line for cell_line in cell_lines if cell_line != ""]
        for cell_line in cell_lines:
            self.app.sendline(cell_line)
            self.app.expect(PROMPT, timeout=TIMEOUT)
            output = self.app.before.decode()
            output = output.replace("\r\n", "\n")
            output = output.split("\n")
            output = [output_line.strip() for output_line in output]
            for output_line in output:
                if output_line not in cell_lines:
                    print(output_line)
        return None

    @line_magic
    def quit(self, line):
        self.app.sendline(QUIT)


def load_ipython_extension(ip):
    ip.register_magics(Magic(ip))


load_ipython_extension(ip=get_ipython())

Preparación#

[2]:
#
# Crea la carpeta drivers en el HDFS
#
!hdfs dfs -rm -r -f /tmp/drivers
!hdfs dfs -mkdir    /tmp/drivers
Deleted /tmp/drivers
[3]:
!wget https://raw.githubusercontent.com/jdvelasq/datalabs/master/datasets/drivers/drivers.csv
--2022-05-17 16:15:55--  https://raw.githubusercontent.com/jdvelasq/datalabs/master/datasets/drivers/drivers.csv
Resolving raw.githubusercontent.com (raw.githubusercontent.com)... 185.199.110.133, 185.199.111.133, 185.199.108.133, ...
Connecting to raw.githubusercontent.com (raw.githubusercontent.com)|185.199.110.133|:443... connected.
HTTP request sent, awaiting response... 200 OK
Length: 2043 (2.0K) [text/plain]
Saving to: ‘drivers.csv’

drivers.csv         100%[===================>]   2.00K  --.-KB/s    in 0.001s

2022-05-17 16:15:56 (2.69 MB/s) - ‘drivers.csv’ saved [2043/2043]

[4]:
!wget https://raw.githubusercontent.com/jdvelasq/datalabs/master/datasets/drivers/drivers.json
--2022-05-17 16:15:56--  https://raw.githubusercontent.com/jdvelasq/datalabs/master/datasets/drivers/drivers.json
Resolving raw.githubusercontent.com (raw.githubusercontent.com)... 185.199.110.133, 185.199.111.133, 185.199.108.133, ...
Connecting to raw.githubusercontent.com (raw.githubusercontent.com)|185.199.110.133|:443... connected.
HTTP request sent, awaiting response... 200 OK
Length: 4308 (4.2K) [text/plain]
Saving to: ‘drivers.json’

drivers.json        100%[===================>]   4.21K  --.-KB/s    in 0.002s

2022-05-17 16:15:56 (1.80 MB/s) - ‘drivers.json’ saved [4308/4308]

Lectura de formato JSON desde un archivo cargado como texto#

En esta estrategía de carga de datos, el archivo original con formato JSON es cargado como texto, donde cada registro de la tabla corresponde a una línea del archivo original.

[5]:
#
# Copia el archivo al HDFS para su importación posterior a Hive
#
!hdfs dfs -copyFromLocal drivers.json  /tmp/drivers/
[6]:
!hdfs dfs -ls /tmp/drivers/
Found 1 items
-rw-r--r--   1 root supergroup       4308 2022-05-17 16:15 /tmp/drivers/drivers.json

En la siguiente celda, se crea la tabla drivers_raw_json, la cual tiene una única columna llamada textcol. Luego, el archivo drivers.json es cargado en dicha tabla. Finalmente, se visualizan los primeros cinco registros para verificar que la lectura fue correcta.

[7]:
%%hive
DROP TABLE IF EXISTS drivers_raw_json;

CREATE TABLE drivers_raw_json (
    textcol STRING
)
STORED AS TEXTFILE;

LOAD DATA INPATH
    '/tmp/drivers/drivers.json'
OVERWRITE INTO TABLE drivers_raw_json;

SELECT * FROM drivers_raw_json LIMIT 5;
OK
Time taken: 5.677 seconds
OK
Time taken: 0.554 seconds
Loading data to table default.drivers_raw_json
OK
Time taken: 0.622 seconds
OK
{"driverId":10,"name":"George Vetticaden","ssn":621011971,"location":"244-4532 Nulla Rd.","certified":"N","wage-plan":"miles"}
{"driverId":11,"name":"Jamie Engesser","ssn":262112338,"location":"366-4125 Ac Street","certified":"N","wage-plan":"miles"}
{"driverId":12,"name":"Paul Coddin","ssn":198041975,"location":"Ap #622-957 Risus. Street","certified":"Y","wage-plan":"hours"}
{"driverId":13,"name":"Joe Niemiec","ssn":139907145,"location":"2071 Hendrerit. Ave","certified":"Y","wage-plan":"hours"}
{"driverId":14,"name":"Adis Cesir","ssn":820812209,"location":"Ap #810-1228 In St.","certified":"Y","wage-plan":"hours"}
Time taken: 1.021 seconds, Fetched: 5 row(s)

Note que en la salida anterior, cada fila corresponde a un registro.

Lectura usando get_json_object#

Los valores de los campos pueden ser extraídos usando la función get_json_object, cuyos parámetros son el nombre del campo en la tabla y el nombre del campo en la estructura JSON. En el siguiente fragmento de código, se utiliza una consulta para extraer los campos driverId, name y ssn.

[8]:
%%hive
SELECT
    GET_JSON_OBJECT(textcol,'$.driverId'),
    GET_JSON_OBJECT(textcol,'$.name'),
    GET_JSON_OBJECT(textcol,'$.ssn')
FROM
    drivers_raw_json
LIMIT
    10;
OK
10      George Vetticaden       621011971
11      Jamie Engesser  262112338
12      Paul Coddin     198041975
13      Joe Niemiec     139907145
14      Adis Cesir      820812209
15      Rohit Bakshi    239005227
16      Tom McCuch      363303105
17      Eric Mizell     123808238
18      Grant Liu       171010151
19      Ajay Singh      160005158
Time taken: 0.315 seconds, Fetched: 10 row(s)

Uso de json_tuple#

Esta función cumple el mismo objetivo de la anterior, pero es mucho más eficiente ya que el registro es procesado únicamente una vez para realizar la extracción de la información requerida. Ya que json_tuple es una UDF, debe usarse LATERAL VIEW para realizar la consulta, tal como se ejemplifica a continuación.

[9]:
%%hive
SELECT
    t1.driverId,
    t1.name,
    t1.ssn
FROM
    drivers_raw_json  t0
LATERAL VIEW
    JSON_TUPLE(t0.textcol, 'driverId', 'name', 'ssn') t1
    AS driverId, name, ssn
LIMIT 5;
OK
10      George Vetticaden       621011971
11      Jamie Engesser  262112338
12      Paul Coddin     198041975
13      Joe Niemiec     139907145
14      Adis Cesir      820812209
Time taken: 0.078 seconds, Fetched: 5 row(s)

Carga de archivos en formato JSON#

Hive también permite la importación directa de archivos en formato JSON usando el serde JsonSerDe.

[10]:
#
# Se copia el archivo al sistema HDFS
#
!hdfs dfs -copyFromLocal drivers.*  /tmp/drivers/

En la siguiente celda, se crea la tabla drivers_json donde el formato de cada registro es especificado como JSON

[11]:
%%hive
DROP TABLE IF EXISTS drivers_json;

CREATE TABLE drivers_json (
    driverId  INT,
    name      STRING,
    ssn       BIGINT,
    location  STRING,
    certified STRING,
    wageplan  STRING)
ROW FORMAT SERDE 'org.apache.hive.hcatalog.data.JsonSerDe'
STORED AS TEXTFILE
LOCATION '/tmp/drivers-json';

LOAD DATA INPATH '/tmp/drivers/drivers.json' OVERWRITE INTO TABLE drivers_json;

SELECT * FROM drivers_json LIMIT 5;
OK
Time taken: 0.021 seconds
OK
Time taken: 0.065 seconds
json;DATA INPATH '/tmp/drivers/drivers.json' OVERWRITE INTO TABLE drivers_
Loading data to table default.drivers_json
OK
Time taken: 0.23 seconds
OK
10      George Vetticaden       621011971       244-4532 Nulla Rd.      N       NULL
11      Jamie Engesser  262112338       366-4125 Ac Street      N       NULL
12      Paul Coddin     198041975       Ap #622-957 Risus. Street       Y       NULL
13      Joe Niemiec     139907145       2071 Hendrerit. Ave     Y       NULL
14      Adis Cesir      820812209       Ap #810-1228 In St.     Y       NULL
Time taken: 0.102 seconds, Fetched: 5 row(s)

Carga de archivos en formato CSV#

En este ejemplo se usa el serde OpenCSVSerde para leer archivo en formato CSV. Note que se usa la cláusula with serdeproperties para indicar las características del formato CSV utilizado.

[12]:
%%hive
DROP TABLE IF EXISTS drivers_csv;

CREATE TABLE drivers_csv (driverId  INT,
                         name      STRING,
                         ssn       BIGINT,
                         location  STRING,
                         certified STRING,
                         wageplan  STRING)
ROW FORMAT SERDE
    'org.apache.hadoop.hive.serde2.OpenCSVSerde'
WITH SERDEPROPERTIES (
   'separatorChar' = ",",
   'quoteChar'     = '\'',
   'escapeChar'    = "\\");

LOAD DATA INPATH '/tmp/drivers/drivers.csv' OVERWRITE INTO TABLE drivers_csv;

SELECT * FROM drivers_csv LIMIT 5;
OK
Time taken: 0.024 seconds
OK
Time taken: 0.058 seconds
sv;D DATA INPATH '/tmp/drivers/drivers.csv' OVERWRITE INTO TABLE drivers_c
Loading data to table default.drivers_csv
OK
Time taken: 0.204 seconds
OK
driverId        name    ssn     location        certified       wage-plan
10      George Vetticaden       621011971       244-4532 Nulla Rd.      N       miles
11      Jamie Engesser  262112338       366-4125 Ac Street      N       miles
12      Paul Coddin     198041975       Ap #622-957 Risus. Street       Y       hours
13      Joe Niemiec     139907145       2071 Hendrerit. Ave     Y       hours
Time taken: 0.103 seconds, Fetched: 5 row(s)

Carga usando expresiones regulaes y RegexSerDe#

En este caso, se realiza la carga de datos especificando los campos mediante el uso de expresiones regulares.

[13]:
#
# Copia los archivos al HDFS
#
!hdfs dfs -copyFromLocal drivers.csv  /tmp/drivers/
[14]:
%%hive
DROP TABLE IF EXISTS drivers_regex;

CREATE TABLE drivers_regex(
    driverId  INT,
    name      STRING,
    ssn       BIGINT,
    location  STRING,
    certified STRING,
    wageplan  STRING)
ROW FORMAT SERDE
    'org.apache.hadoop.hive.serde2.RegexSerDe'
WITH SERDEPROPERTIES (
   'input.regex' = '(\\d+),([^,]*),(\\d+),([^,]*),([^,]*),([^,]*)')
TBLPROPERTIES ("skip.header.line.count"="1");

LOAD DATA INPATH '/tmp/drivers/drivers.csv' OVERWRITE INTO TABLE drivers_regex;

SELECT * FROM drivers_regex LIMIT 5;
OK
Time taken: 0.019 seconds
OK
Time taken: 0.059 seconds
egex;DATA INPATH '/tmp/drivers/drivers.csv' OVERWRITE INTO TABLE drivers_r
Loading data to table default.drivers_regex
OK
Time taken: 0.208 seconds
OK
10      George Vetticaden       621011971       244-4532 Nulla Rd.      N       miles
11      Jamie Engesser  262112338       366-4125 Ac Street      N       miles
12      Paul Coddin     198041975       Ap #622-957 Risus. Street       Y       hours
13      Joe Niemiec     139907145       2071 Hendrerit. Ave     Y       hours
14      Adis Cesir      820812209       Ap #810-1228 In St.     Y       hours
Time taken: 0.096 seconds, Fetched: 5 row(s)

La expresión regular usada es la siguiente:

(\\d+),([^,]*),(\\d+),([^,]*),([^,]*),([^,]*)`

donde:

  • Los paréntesis indica los campos, esto es, (\\d+) es el primer campo, ([^,]*) es el segundo y así sucesivamente.

  • Se indica que la coma es el separador entre campos.

  • (\\d+) representa una cadena de uno o más dígitos.

  • [...] representan uno o más posibles caracteres, de tal forma que [^,] indica cualquier caracter excepto una coma. Finalmente, el * indica cero, una o más ocurrencias. Es así como [^,]* representa cualquier cadena de caracteres que no contenga una coma.

  • La expresión regular usada indica que los campos 1 y 3 son numéricos, y los restantes son texto.

[15]:
%quit
[16]:
!rm drivers.* *.log