如何将 Hive 表导出为 CSV 文件?

Posted

技术标签:

【中文标题】如何将 Hive 表导出为 CSV 文件?【英文标题】:How to export a Hive table into a CSV file? 【发布时间】:2013-06-09 19:31:22 【问题描述】:

我使用此 Hive 查询将表导出到 CSV 文件中。

INSERT OVERWRITE DIRECTORY '/user/data/output/test' select column1, column2 from table1;

生成的文件“000000_0”没有逗号分隔符

这是生成 CSV 文件的正确方法吗?如果没有,请告诉我如何生成 CSV 文件?

【问题讨论】:

【参考方案1】:

这是在 Hive 的 SQL 中更简单的方法:

set hive.execution.engine=tez;
set hive.merge.tezfiles=true;
set hive.exec.compress.output=false;

INSERT OVERWRITE DIRECTORY '/tmp/job/'
ROW FORMAT DELIMITED
FIELDS TERMINATED by ','
NULL DEFINED AS ''
STORED AS TEXTFILE
SELECT * from table;

【讨论】:

【参考方案2】:

试试

hive --outputformat==csv2 -e "select * from YOUR_TABLE";

这对我有用

我的 hive 版本是“Hive 3.1.0.3.1.0.0-78”

【讨论】:

【参考方案3】:

或者使用这个

hive -e 'select * from your_Table' | sed 's/[\t]/,/g'  > /home/yourfile.csv

您还可以在SELECT 之前指定属性set hive.cli.print.header=true,以确保创建标头和数据并将其复制到文件中。 例如:

hive -e 'set hive.cli.print.header=true; select * from your_Table' | sed 's/[\t]/,/g'  > /home/yourfile.csv

如果您不想写入本地文件系统,请使用hadoop fs -put 命令将sed 命令的输出传送回HDFS

使用Cyberduck 之类的方式将文件通过 SFTP 传输到您的文件可能也很方便,或者您可以使用 scp 通过终端/命令提示符进行连接。

【讨论】:

通过使用此命令,'double' 等 hive 数据类型不会在 CSV 中结转。因此,当我阅读 CSV 时,所有内容都被读取为字符串。 在hive cli被beeline替换的hive版本3中,查询的输出略有不同,因为它包含格式 我尝试将其导出以将 hive 查询导出到本地和 hdfs 文件,但无法从 spark 会话中读取相同的文件 - 标头未正确识别!【参考方案4】:

下面是我用来将 Hive 表数据导出到 HDFS 作为带有标题的单个命名 CSV 文件的端到端解决方案。 (不幸的是,不可能只使用一个 HQL 语句) 它由几个命令组成,但我认为它非常直观,并且它不依赖于 Hive 表的内部表示,它可能会不时改变。 如果要将数据导出到本地文件系统而不是 HDFS,请将“DIRECTORY”替换为“LOCAL DIRECTORY”。

# cleanup the existing target HDFS directory, if it exists
sudo -u hdfs hdfs dfs -rm -f -r /tmp/data/my_exported_table_name/*

# export the data using Beeline CLI (it will create a data file with a surrogate name in the target HDFS directory)
beeline -u jdbc:hive2://my_hostname:10000 -n hive -e "INSERT OVERWRITE DIRECTORY '/tmp/data/my_exported_table_name' ROW FORMAT DELIMITED FIELDS TERMINATED BY ',' SELECT * FROM my_exported_table_name"

# set the owner of the target HDFS directory to whatever UID you'll be using to run the subsequent commands (root in this case)
sudo -u hdfs hdfs dfs -chown -R root:hdfs /tmp/data/my_exported_table_name

# write the CSV header record to a separate file (make sure that its name is higher in the sort order than for the data file in the target HDFS directory)
# also, obviously, make sure that the number and the order of fields is the same as in the data file
echo 'field_name_1,field_name_2,field_name_3,field_name_4,field_name_5' | hadoop fs -put - /tmp/data/my_exported_table_name/.header.csv

# concatenate all (2) files in the target HDFS directory into the final CSV data file with a header
# (this is where the sort order of the file names is important)
hadoop fs -cat /tmp/data/my_exported_table_name/* | hadoop fs -put - /tmp/data/my_exported_table_name/my_exported_table_name.csv

# give the permissions for the exported data to other users as necessary
sudo -u hdfs hdfs dfs -chmod -R 777 /tmp/data/hive_extr/drivers

【讨论】:

【参考方案5】:

问题解决方案很好,但我发现两者都有一些问题:

正如 Carter Shanklin 所说,使用此命令,我们将在指定的路径中获得一个带有查询结果的 csv 文件:

insert overwrite local directory '/home/carter/staging' row format delimited fields terminated by ',' select * from hugetable;

这个解决方案的问题是获得的 csv 没有标题,并且会创建一个不是 CSV 的文件(所以我们必须重命名它)。

正如user1922900所说,使用以下命令我们将获得一个CSV文件,其中包含指定文件中的查询结果和标题:

hive -e 'select * from some_table' | sed 's/[\t]/,/g' > /home/yourfile.csv

使用此解决方案,我们将获得一个包含查询结果行的 CSV 文件,但这些行之间也包含日志消息。作为这个问题的解决方案,我尝试了this,但没有结果。

所以,为了解决所有这些问题,我创建了一个脚本来执行查询列表,创建一个文件夹(带有时间戳)来存储结果,重命名获得的文件,删除不需要的文件,并添加相应的标题。

 #!/bin/sh
 QUERIES=("select * from table1" "select * from table2")
 IFS=""
 directoryname=$(echo "ScriptResults$timestamp")
 mkdir $directoryname 
 counter=1 
for query in $QUERIES[*]
 do 
     tablename="query"$counter 
     hive -S -e "INSERT OVERWRITE LOCAL DIRECTORY '/data/2/DOMAIN_USERS/SANUK/users/$USER/$tablename' ROW FORMAT DELIMITED FIELDS TERMINATED BY ',' $query ;"
     hive -S -e "set hive.cli.print.header=true; $query limit 1" | head -1 | sed 's/[\t]/,/g' >> /data/2/DOMAIN_USERS/SANUK/users/$USER/$tablename/header.csv
     mv $tablename/000000_0 $tablename/$tablename.csv
     cat $tablename/$tablename.csv >> $tablename/header.csv.
     rm $tablename/$tablename.csv
     mv $tablename/header.csv $tablename/$tablename.csv 
     mv $tablename/$tablename.csv $directoryname
     counter=$((counter+1))
     rm -rf $tablename/ 
 done

【讨论】:

【参考方案6】:

如果您是从 Windows 执行此操作,您可以使用 Python 脚本 hivehoney 将表数据提取到本地 CSV 文件。

它会:

登录堡垒主机。 pbrun。 启动。 直线(与您的查询)。 保存 从直线回显到 Windows 上的文件。

这样执行:

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

【讨论】:

【参考方案7】:

以下脚本应该适合您:

#!/bin/bash
hive -e "insert overwrite local directory '/LocalPath/'
row format delimited fields terminated by ','
select * from Mydatabase,Mytable limit 100"
cat /LocalPath/* > /LocalPath/table.csv

我用limit 100来限制数据的大小,因为我有一个很大的表,但是你可以删除它来导出整个表。

【讨论】:

【参考方案8】:

在这里使用 Hive 仓库目录,您可以导出数据而不是 Hive 表。 首先给出 hive 仓库路径,然后是要存储 .csv 文件的本地路径 对于此命令如下:-

hadoop fs -cat /user/hdusr/warehouse/HiveDb/tableName/* > /users/hadoop/test/nilesh/sample.csv

【讨论】:

【参考方案9】:

这应该适合你

制表符分隔

hive -e 'select * from some_table' > /home/yourfile.tsv

逗号分隔

hive -e 'select * from some_table' | sed 's/[\t]/,/g' > /home/yourfile.csv

【讨论】:

这将导出为制表符分隔 它正在工作:hive -e 'use ;从 中选择 *;' > /.csv 请注意,在大公司中,通常您必须为这样的工作分配队列名称,-hiveconf 发挥作用,否则您无法运行它。 @Lihaonan,我如何在查询中分配队列名?【参考方案10】:
INSERT OVERWRITE LOCAL DIRECTORY '/home/lvermeer/temp' ROW FORMAT DELIMITED FIELDS TERMINATED BY ',' select * from table; 

是正确的答案。

如果记录数真的很大,以生成的文件数为准

以下命令只会给出部分结果。

hive -e 'select * from some_table' > /home/yourfile.csv

【讨论】:

我该如何处理这个错误消息:User user_id does not have privileges for QUERY? 检查 Ranger 的政策是否存在 hive 权限错误【参考方案11】:

如果您使用的是 Hive 11 或更高版本,则可以使用带有 LOCAL 关键字的 INSERT 语句。

例子:

insert overwrite local directory '/home/carter/staging' row format delimited fields terminated by ',' select * from hugetable;

请注意,这可能会创建多个文件,您可能希望在完成导出后在客户端将它们连接起来。

使用这种方式意味着您无需担心源表的格式,可以根据任意 SQL 查询导出,并且可以选择自己的分隔符和输出格式。

【讨论】:

谢谢,这个创建的文件夹包含多个 csv 文件。有没有办法把所有东西都放在一个文件中?还有是否在 csv 文件中包含标题(列名)? 导出后如何在客户端连接它们? 对我来说,这个命令产生了一堆以扩展名 .snappy 结尾的文件,看起来像是一种压缩格式。我不确定如何转换解压缩它们。我知道如何在本地机器上使用命令cat file1 file2 > file 在本地合并文件。【参考方案12】:

最近版本的 hive 带有此功能。

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

这样您可以选择自己的分隔符和文件名。 请注意“OVERWRITE”,它会尝试从提到的文件夹中删除所有内容。

【讨论】:

【参考方案13】:

我使用简单的 linux shell 管道 + perl 将 hive 生成​​的输出从 tsv 转换为 csv。

hive -e "SELECT col1, col2, … FROM table_name" | perl -lpe 's/"/\\"/g; s/^|$/"/g; s/\t/","/g' > output_file.csv

(前段时间我从 *** 中的某个人那里得到了更新的 perl 正则表达式)

结果会像普通的 csv:

"col1","col2","col3"...等等

【讨论】:

【参考方案14】:

有一些方法可以更改默认分隔符,如其他答案所示。

还有一些方法可以使用一些 bash 脚本将原始输出转换为 csv。不过,有 3 个分隔符需要考虑,而不仅仅是 \001。当您的 hive 表有 maps 时,事情会变得有点复杂。

我编写了一个 bash 脚本,它可以处理来自 hive 的所有 3 个默认分隔符(\001 \002 和 \003)并输出一个 csv。脚本和更多信息在这里:

CSV 的 Hive 默认分隔符

Hive 的默认分隔符是

Row Delimiter => Control-A ('\001')
Collection Item Delimiter => Control-B ('\002')
Map Key Delimiter => Control-C ('\003')

导出表格时有一些方法可以更改这些分隔符,但是 有时您可能仍然需要将其转换为 csv。

这是一个可以处理数据库导出的快速 bash 脚本 在多个文件中分段并具有默认分隔符。它会 输出单个 CSV 文件。

假设段都具有命名约定 000*_0

INDIRECTORY="path/to/input/directory"
for f in $INDIRECTORY/000*_0; do 
  echo "Processing $f file.."; 
  cat -v $f | 
      LC_ALL=C sed -e "s/^/\"/g" | 
      LC_ALL=C sed -e "s/\^A/\",\"/g" | 
      LC_ALL=C sed -e "s/\^C\^B/\"\":\"\"\"\",\"\"/g" | 
      LC_ALL=C sed -e "s/\^B/\"\",\"\"/g" |  
      LC_ALL=C sed -e "s/\^C/\"\":\"\"/g" | 
      LC_ALL=C sed -e "s/$/\"/g" > $f-temp
done
echo "you,can,echo,your,header,here,if,you,like" > $INDIRECTORY/final_output.csv
cat $INDIRECTORY/*-temp >> $INDIRECTORY/final_output.csv
rm $INDIRECTORY/*-temp

更多解释the gist

【讨论】:

【参考方案15】:

我遇到了类似的问题,这就是我能够解决的方法。

第 1 步 - 将 hive 表中的数据加载到另一个表中,如下所示

如果存在则删除表 TestHiveTableCSV; CREATE TABLE TestHiveTableCSV 行格式分隔的字段以 ',' 终止的行为 '\n' AS 从 TestHiveTable 中选择列列表;

第 2 步 - 将 blob 从 hive 仓库复制到具有适当扩展名的新位置

开始-AzureStorageBlobCopy -DestContext $destContext -SrcContainer“源容器” -SrcBlob "hive/warehouse/TestHiveTableCSV/000000_0" -DestContainer“目标容器”` -DestBlob "CSV/TestHiveTable.csv"

希望这会有所帮助!

最好的问候, Dattatrey Sindol (达塔) http://dattatreysindol.com

【讨论】:

【参考方案16】:

在生成报告后(如您所做的那样),您不能为查询输出设置分隔符。

您可以将分隔符更改为逗号。

它带有默认分隔符\001(不可见字符)。

hadoop fs -cat /user/data/output/test/* |tr "\01" "," >>outputwithcomma.csv

check this also

【讨论】:

以上是关于如何将 Hive 表导出为 CSV 文件?的主要内容,如果未能解决你的问题,请参考以下文章

如何把SQLServer表数据导出CSV文件

如何从Oracle到hive

导出 Hive 查询结果

如何将 CSV 文件中的数据插入 Hive?

HIVE数据导出CSV

hive表数据导出到csv乱码原因及解决方案