¿Cómo envío los resultados de una consulta HiveQL a CSV?

81

nos gustaría poner los resultados de una consulta de Hive en un archivo CSV. Pensé que el comando debería verse así:

insert overwrite directory '/home/output.csv' select books from table;

Cuando lo ejecuto, dice que se completó correctamente, pero nunca puedo encontrar el archivo. ¿Cómo encuentro este archivo o debo extraer los datos de otra manera?

AAA
fuente

Respuestas:

146

Aunque se puede utilizar INSERT OVERWRITEpara obtener datos de Hive, es posible que no sea el mejor método para su caso particular. Primero déjeme explicar qué INSERT OVERWRITEhace, luego describiré el método que uso para obtener archivos tsv de las tablas de Hive.

Según el manual , su consulta almacenará los datos en un directorio en HDFS. El formato no será csv.

Los datos escritos en el sistema de archivos se serializan como texto con columnas separadas por ^ A y filas separadas por líneas nuevas. Si alguna de las columnas no es de tipo primitivo, esas columnas se serializan en formato JSON.

Una ligera modificación (agregando la LOCALpalabra clave) almacenará los datos en un directorio local.

INSERT OVERWRITE LOCAL DIRECTORY '/home/lvermeer/temp' select books from table;

Cuando ejecuto una consulta similar, así es como se ve el resultado.

[lvermeer@hadoop temp]$ ll
total 4
-rwxr-xr-x 1 lvermeer users 811 Aug  9 09:21 000000_0
[lvermeer@hadoop temp]$ head 000000_0 
"row1""col1"1234"col3"1234FALSE
"row2""col1"5678"col3"5678TRUE

Personalmente, generalmente ejecuto mi consulta directamente a través de Hive en la línea de comando para este tipo de cosas, y la canalizo al archivo local de esta manera:

hive -e 'select books from table' > /home/lvermeer/temp.tsv

Eso me da un archivo separado por tabulaciones que puedo usar. Espero que también te sea útil.

Basado en este parche-3682 , sospecho que hay una mejor solución disponible cuando se usa Hive 0.11, pero no puedo probarlo por mí mismo. La nueva sintaxis debería permitir lo siguiente.

INSERT OVERWRITE LOCAL DIRECTORY '/home/lvermeer/temp' 
ROW FORMAT DELIMITED 
FIELDS TERMINATED BY ',' 
select books from table;

Espero que ayude.

Lukas Vermeer
fuente
2
¿Conoce alguna diferencia de rendimiento entre insertar sobrescribir local y canalizar, en qué volumen aproximado puede convertirse en un problema? Además, la canalización garantiza que obtendrá un archivo, ya que el otro enfoque nos da un directorio que potencialmente necesitamos fusionar después
fd8s0
¿Es posible exportar los datos en HDFS como formato de archivo de secuencia?
Nageswaran
1
Probé la solución (parche-3682) y funcionó bien para mí, excepto que, por alguna razón, el archivo de salida no incluía los encabezados. Tenga en cuenta que he establecido hive.cli.print.header = true; en mi .hiverc. Por lo que vale la pena, los encabezados se imprimieron en la terminal (que obviamente no es lo que quería).
Peter Cogan
@ lukas-vermeer, cuando crea la tabla usando el método "INSERT OVERWRITE", la información del encabezado se pierde. ¿Hay alguna forma de obtener la información del encabezado?
ML_Passion
Hola Lukas, ¿cómo hiciste que tu shell funcionara en el sistema de archivos hadoop?
notilas
23

Si desea un archivo CSV, puede modificar las soluciones de Lukas de la siguiente manera (asumiendo que está en una caja de Linux):

hive -e 'select books from table' | sed 's/[[:space:]]\+/,/g' > /home/lvermeer/temp.csv
David Kjerrumgaard
fuente
4
Gracias por esto. Estoy usando una variación, pero funciona muy bien. Tenga en cuenta que esto generará un resultado delimitado por comas, no necesariamente lo que algunas personas consideran CSV. CSV generalmente tiene algún formato para manejar datos con comas (por ejemplo, ajustar los datos con comillas dobles y comillas dobles para datos con comillas dobles). Vale la pena mencionar que agregar el parámetro "--hiveconf hive.cli.print.header = True" también obtendrá los encabezados en la salida.
jatal
Esta es la solución más limpia
Dutta
1
Esto falló para mí, por ejemplo, una cadena de fecha y hora que tenía un espacio entre la fecha y la hora.
williaster
@williaster sed 's / \ t \ + /, / g' esto debería ayudar para este problema.
Sudhakar Chavan
Esto no funcionaría si el tsv tiene texto que contiene comas. (porque las comas de cadena inocentes sin comillas se tratarán como separadores)
yahiaelgamal
4

Debe utilizar la instrucción CREATE TABLE AS SELECT (CTAS) para crear un directorio en HDFS con los archivos que contienen los resultados de la consulta. Después de eso, tendrá que exportar esos archivos de HDFS a su disco normal y fusionarlos en un solo archivo.

También es posible que tenga que hacer algunos trucos para convertir los archivos de '\ 001' - delimitados a CSV. Puede utilizar un CSV SerDe personalizado o posprocesar el archivo extraído.

Olaf
fuente
Este enfoque es mejor si se desea utilizar la salida en un paso posterior de la canalización de Oozie.
Cerd
4

Puede utilizar INSERT…… DIRECTORY, como en este ejemplo:

INSERT OVERWRITE LOCAL DIRECTORY '/tmp/ca_employees'
SELECT name, salary, address
FROM employees
WHERE se.state = 'CA';

OVERWRITEy LOCALtienen las mismas interpretaciones que antes y los caminos se interpretan siguiendo las reglas habituales. Se escribirán uno o más archivos /tmp/ca_employees, según el número de reductores invocados.

grandes fabricantes
fuente
3

Si está utilizando HUE, esto también es bastante simple. Simplemente vaya al editor de Hive en HUE, ejecute su consulta de Hive, luego guarde el archivo de resultados localmente como XLS o CSV, o puede guardar el archivo de resultados en HDFS.

Rayo
fuente
3

Estaba buscando una solución similar, pero las mencionadas aquí no funcionarían. Mis datos tenían todas las variaciones de espacios en blanco (espacio, nueva línea, tabulación) caracteres y comas.

Para hacer que los datos de la columna sean seguros, reemplacé todos los caracteres \ t en los datos de la columna con un espacio y ejecuté el código de Python en la línea de comandos para generar un archivo csv, como se muestra a continuación:

hive -e 'tab_replaced_hql_query' |  python -c 'exec("import sys;import csv;reader = csv.reader(sys.stdin, dialect=csv.excel_tab);writer = csv.writer(sys.stdout, dialect=csv.excel)\nfor row in reader: writer.writerow(row)")'

Esto creó un csv perfectamente válido. Espero que esto ayude a aquellos que vienen buscando esta solución.

sisanared
fuente
1
¿Es 2016 y todavía tenemos que pasar por el aro para hacer esto? Encontré que la solución de shravster es la mejor y más elegante solución hasta ahora.
Josh
¿Cómo reemplazó todos los caracteres \ t en los datos de la columna? ¿Lo abordó en la consulta o creó una vista separada para él?
Naresh S
@NareshS, perdón por la respuesta tardía. Sí, las columnas se manejaron en colmena para reemplazar las pestañas con espacios o, si son esenciales, puede reemplazarlas con un sustituto como <: pestaña>, o algo por el estilo
sisanared
@sisanared, Gracias por la respuesta. Veo que necesitamos usar regex replace para todas las columnas de cadenas y esto sería engorroso si tenemos una tabla con una gran cantidad de columnas> 100. ¿Existe una solución rápida para tal caso
Naresh S
@NareshS, desafortunadamente, la única otra solución es limpiar los datos antes de ponerlos en sus particiones. De lo contrario, tendrá que hacerlo mientras realiza la selección para todas las columnas de cadena que podrían contener caracteres de tabulación
sisanared
3

Puede usar la función de cadena de colmena CONCAT_WS( string delimiter, string str1, string str2...strn )

por ejemplo:

hive -e 'select CONCAT_WS(',',cola,colb,colc...,coln) from Mytable' > /home/user/Mycsv.csv
Ram Ghadiyaram
fuente
3

Esta es la forma más amigable de csv que encontré para generar los resultados de HiveQL.
No necesita ningún comando grep o sed para formatear los datos, en su lugar, hive lo admite, solo necesita agregar una etiqueta adicional de formato de salida.

hive --outputformat=csv2 -e 'select * from <table_name> limit 20' > /path/toStore/data/results.csv
Rishabh Sachdeva
fuente
2

Tuve un problema similar y así fue como pude abordarlo.

Paso 1 : cargó los datos de la tabla Hive en otra tabla de la siguiente manera

DROP TABLE IF EXISTS TestHiveTableCSV;
CREATE TABLE TestHiveTableCSV 
ROW FORMAT DELIMITED 
FIELDS TERMINATED BY ','
LINES TERMINATED BY '\n' AS
SELECT Column List FROM TestHiveTable;

Paso 2 : copió el blob del almacén de Hive en la nueva ubicación con la extensión adecuada

Start-AzureStorageBlobCopy
-DestContext $destContext 
-SrcContainer "Source Container"
-SrcBlob "hive/warehouse/TestHiveTableCSV/000000_0"
-DestContainer "Destination Container"
-DestBlob "CSV/TestHiveTable.csv"
Dattatrey Sindol
fuente
2
hive  --outputformat=csv2 -e "select * from yourtable" > my_file.csv

o

hive  --outputformat=csv2 -e "select * from yourtable" > [your_path]/file_name.csv

Para tsv, simplemente cambie csv a tsv en las consultas anteriores y ejecute sus consultas

Terminator17
fuente
1

El separador predeterminado es " ^A". En lenguaje Python, es " \x01".

Cuando quiero cambiar el delimitador, uso SQL como:

SELECT col1, delimiter, col2, delimiter, col3, ..., FROM table

Luego, considere delimitador + " ^A" como un nuevo delimitador.

moshaholo
fuente
1

Probé varias opciones, pero esta sería una de las soluciones más simples para Python Pandas:

hive -e 'select books from table' | grep "|" ' > temp.csv

df=pd.read_csv("temp.csv",sep='|')

También puede utilizar tr "|" ","para convertir "|" a ","

notilas
fuente
0

Similar a la respuesta de Ray anterior, Hive View 2.0 en Hortonworks Data Platform también le permite ejecutar una consulta de Hive y luego guardar la salida como csv.

Schoon
fuente
0

En caso de que lo esté haciendo desde Windows, puede usar el script de Python hivehoney para extraer los datos de la tabla al archivo CSV local.

Va a:

  1. Inicie sesión en el servidor bastión.
  2. pbrun.
  3. kinit.
  4. beeline (con su consulta).
  5. Guarde el eco de beeline en un archivo en Windows.

Ejecútelo así:

set PROXY_HOST=your_bastion_host

set SERVICE_USER=you_func_user

set LINUX_USER=your_SOID

set LINUX_PWD=your_pwd

python hh.py --query_file=query.sql
Alex B
fuente
0

Solo para cubrir más pasos siguientes después de iniciar la consulta: INSERT OVERWRITE LOCAL DIRECTORY '/home/lvermeer/temp' ROW FORMAT DELIMITED FIELDS TERMINATED BY ',' select books from table;

En mi caso, los datos generados en la carpeta temporal están en deflateformato y se ve así:

$ ls
000000_0.deflate  
000001_0.deflate  
000002_0.deflate  
000003_0.deflate  
000004_0.deflate  
000005_0.deflate  
000006_0.deflate  
000007_0.deflate

Aquí está el comando para descomprimir los archivos desinflados y poner todo en un archivo csv:

hadoop fs -text "file:///home/lvermeer/temp/*" > /home/lvermeer/result.csv
JohnnyHuo
fuente
0

Puede que llegue tarde a este, pero ayudaría con la respuesta:

echo "COL_NAME1 | COL_NAME2 | COL_NAME3 | COL_NAME4"> SAMPLE_Data.csv colmena -e 'seleccionar concat distinto (COL_1, "|", COL_2, "|", COL_3, "|", COL_4) de table_Name donde la cláusula si es necesario;' >> SAMPLE_Data.csv

Anil Kumar
fuente
0

Este comando de shell imprime el formato de salida en csv output.txtsin los encabezados de columna.

$ hive --outputformat=csv2 -f 'hivedatascript.hql' --hiveconf hive.cli.print.header=false > output.txt
Varanasi Sai Bhargav
fuente
0

Usa el comando:

colmena -e "use [nombre_base_datos]; seleccione * de [nombre_tabla] LIMIT 10;" > /ruta/a/archivo/mi_nombre_archivo.csv

Tenía un enorme conjunto de datos cuyos detalles estaba tratando de organizar y determinar los tipos de ataques y los números de cada tipo. Un ejemplo que usé en mi práctica que funcionó (y tenía un poco más de detalles) es algo como esto:

hive -e "use DataAnalysis;
select attack_cat, 
case when attack_cat == 'Backdoor' then 'Backdoors' 
when length(attack_cat) == 0 then 'Normal' 
when attack_cat == 'Backdoors' then 'Backdoors' 
when attack_cat == 'Fuzzers' then 'Fuzzers' 
when attack_cat == 'Generic' then 'Generic' 
when attack_cat == 'Reconnaissance' then 'Reconnaissance' 
when attack_cat == 'Shellcode' then 'Shellcode' 
when attack_cat == 'Worms' then 'Worms' 
when attack_cat == 'Analysis' then 'Analysis' 
when attack_cat == 'DoS' then 'DoS' 
when attack_cat == 'Exploits' then 'Exploits' 
when trim(attack_cat) == 'Fuzzers' then 'Fuzzers' 
when trim(attack_cat) == 'Shellcode' then 'Shellcode' 
when trim(attack_cat) == 'Reconnaissance' then 'Reconnaissance' end,
count(*) from actualattacks group by attack_cat;">/root/data/output/results2.csv
Mungai Gachango
fuente