Hive_4. DML -- 数据转换

前面介绍了 Hive 中的 DDL 语言,接下来我们将具体看看 HIve 中对数据的具体操作。本篇将主要探讨如何使用 LOAD, INSERT, IMPORT 和 EXPORT关键词来进行数据转换操作。

1. 数据转换 – LOAD

在 Hive 中可以通过 LOAD 关键词来移动数据。数据移动代表将数据从原有路径移到目标路径中,相当于剪切操作。以下展示了如果从本地或者 HDFS 中将数据移到 Hive 表(内部表/管理表)或者分区表中。
LOCAL 关键词用来指定文件在主机中的位置,如果 没有被指定,文件将会从INPATH 后指定 完整URL [full Uniform Resource Identifier ]  或者 从Hive 配置属性fs.default.name进行加载。INPATH 后面可以跟相对路径或绝对路径。路径指向的文件或者文件夹(文件夹中所有文件)都会被加载。在path 中不允许指定子目录。

如果要加载数据到分区表,分区字段需要被指定。关键词 OVERWRITE 用来决定是添加还是替换目标表/分区表中的数据。

以下是将文件加载到 Hive 表的示例:

数据加载方式
具体实现方法
Local -> Hive table
将本地数据加载到 Hive 表中: 
jdbc:hive2://> LOAD DATA  LOCAL  INPATH
. . . . . . .> '/home/dayongd/Downloads/employee_hr.txt' 
. . . . . . .>  OVERWRITE  INTO TABLE employee_hr;
No rows affected (0.436 seconds)
Local ->Hive分区表
将本地数据加载到 Hive 分区表中[Hive partition table] :
jdbc:hive2://> LOAD DATA LOCALINPATH
. . . . . . .> '/home/dayongd/Downloads/employee.txt'
. . . . . . .> OVERWRITE INTO TABLE employee_partitioned
. . . . . . .> PARTITION (year=2014, month=12);
No rows affected (0.772 seconds)
使用默认系统路径
使用系统默认路径将 HDFS 数据加载到 Hive 表中: 
jdbc:hive2://> LOAD DATA  INPATH 
. . . . . . .> '/user/dayongd/employee/employee.txt' 
. . . . . . .> OVERWRITE INTO TABLE employee;
No rows affected (0.453 seconds)
使用完整的 URL 
使用完整的 URL [ full URI ] 将数据从 HDFS 加载到 Hive 表中:
jdbc:hive2://> LOAD DATA INPATH 
. . . . . . .> 'hdfs://[dfs_host]:8020/user/dayongd/employee/employee.txt
. . . . . . .> OVERWRITE INTO TABLE employee;
No rows affected (0.297 seconds)

2. 数据转换
– INSERT

我们可以使用 INSERT 关键词来从 Hive 表/分区表中提取数据。类似于关系数据库,Hive 支持从另一张表进行插入,这是我们为一张表填充已有数据的常用方式。 Hive 的 INSERT 语句有一些类似于关系数据库 INSERT 的语法。而且,Hive可以通过支持 OVERWRITEmultiple INSERTdynamic partition INSERT, 将数据插入到文件中来提升了 insert 语句的功能。让我们看一下例子:

  • 以下是标准的利用 SELECT 语句进行插入: 
--检查目标表是否为空.
jdbc:hive2://> SELECT name, work_place, sex_age 
. . . . . . .> FROM employee;
+-------------+-------------------+----------------+
|employee.name|employee.work_place|employee.sex_age|
+-------------+-------------------+----------------+
+-------------+-------------------+----------------+
No rows selected (0.115 seconds)

--利用 Select 出来的数据填充到 employee 表中
jdbc:hive2://>  INSERT INTO  TABLE employee
. . . . . . .> SELECT * FROM ctas_employee;
No rows affected (31.701 seconds)   -- 执行时间太长,基本花在数据的读取,磁盘的I/O

--验证数据的加载
jdbc:hive2://> SELECT name, work_place, sex_age FROM employee;
+-------------+----------------------+-------------------------+
|employee.name| employee.work_place | employee.sex_age |
+-------------+----------------------+-------------------------+
| Michael |["Montreal","Toronto"]|{"sex":"Male","age":30} |
| Will |["Montreal"] |{"sex":"Male","age":35} |
| Shelley |["New York"] |{"sex":"Female","age":27}|
| Lucy |["Vancouver"] |{"sex":"Female","age":57}|
+-------------+----------------------+-------------------------+
4 rows selected (0.12 seconds)
  • 使用公用表表达式 [ CTE - Common Table Expression ] 插入数据:
jdbc:hive2://> WITH a AS (SELECT * FROM ctas_employee )
. . . . . . .> FROM a
. . . . . . .>  INSERT OVERWRITE  TABLE employee
. . . . . . .> SELECT *;
No rows affected (30.1 seconds)
  • 只Scanning 源表一次来执行多次插入: 
jdbc:hive2://> FROM ctas_employee
. . . . . . .>  INSERT OVERWRITE  TABLE employee
. . . . . . .> SELECT *
. . . . . . .>  INSERT OVERWRITE  TABLE employee_internal
. . . . . . .> SELECT * ;
No rows affected (27.919 seconds)

注意:INSERT OVERWRITE 语句 会替换目标表中的数据;INSERT INTO  会将数据附加到表/分区表中。

当向分区表插入数据的时候,我们需要指定分区字段。而不是指定静态分区的静态值。Hive还支持为分区表动态赋值。当数据量很大的时候使用动态分区很有用,此时我们是不知道具体的分区值。例如,日期被动态的用作分区字段。

动态分区默认情况是 Disable 的,我们需要通过设置以下属性来让它正常工作:

jdbc:hive2://> SET hive.exec.dynamic.partition=true;No rows affected (0.002 seconds)

By default, the user must specify at least one static partition column. This is to avoid accidentally overwriting partitions. To disable this restriction, we can set the partition mode to nonstrict from the default strict mode before inserting into dynamic partitions as follows:

默认情况下,用户必须至少指定一个静态分区字段。主要是用来避免分区表覆盖失误。在插入到动态分区之前,你可以通过默认strict 模式中设置分区模式为 nonstrict  来禁止该约束。具体代码如下所示:

jdbc:hive2://> SET hive.exec.dynamic.partition.mode= nonstrict ;
No rows affected (0.002 seconds)

jdbc:hive2://> INSERT INTO TABLE employee_partitioned 
. . . . . . .> PARTITION(year, month)
. . . . . . .> SELECT name, array('Toronto') as work_place, 
. . . . . . .> named_struct("sex","Male","age",30) as sex_age, 
. . . . . . .> map("Python",90) as skills_score,
. . . . . . .> map("R&D",array('Developer')) as depart_title, 
. . . . . . .> year(start_date) as year, month(start_date) as month
. . . . . . .> FROM employee_hr eh
. . . . . . .> WHERE eh.employee_id = 102;
No rows affected (29.024 seconds)

注意:合类型的构造函数通常用来将一个恒定值赋值给一个复合数据类型的列。

Hive INSERT到文件的语句与 LOAD的操作相对应。它从SELECT 语句中提取数据并加载到本地或 HDFS 文件。但是,它目前只支持 OVERWRITE 关键词,不支持 INTO。这意味着我们不能将数据叠加到已有的文件中。默认情况下,列是通过^A 进行分割的,行是通过换行符进行分割。
从 Hive 0.11.0 版本开始,可以指定行分隔符。下面我们将看一些将数据插入到文件的例子:
我们可以使用默认的行分隔符来将数据插入到文件中。在 Hadoop 的一些版本中,本地目录路径只支持2级以下的目录级别。我们可以通过 配置 hive.insert.into.multilevel.dirs=true 参数来解决这个问题。
jdbc:hive2://> INSERT OVERWRITE LOCAL DIRECTORY '/tmp/output1' 
. . . . . . .> SELECT * FROM employee;No rows affected (30.859 seconds)

注意:默认情况下,执行 Insert 操作的时候,大部分的文件是通过reducer 创建的。你可以通过以下的 HDFS 命令来将这些文件整合到一起:

hdfs dfs –getmerge hdfs://<host_name>:8020/user/dayongd/output /tmp/test
  • 利用特定的 行分隔符 将数据插入到本地文件中 :
jdbc:hive2://> INSERT OVERWRITE LOCAL DIRECTORY '/tmp/output2' 
. . . . . . .> ROW FORMAT DELIMITED FIELDS TERMINATED BY ',' 
. . . . . . .> SELECT * FROM employee;
No rows affected (31.937 seconds)

--验证分隔符: 
vi /tmp/output2/000000_0
Michael,Montreal^BToronto,Male^B30,DB^C80,Product^CDeveloper^DLead
Will,Montreal,Male^B35,Perl^C85,Product^CLead^BTest^CLead
Shelley,New York,Female^B27,Python^C80,Test^CLead^BCOE^CArchitect
Lucy,Vancouver,Female^B57,Sales^C89^BHR^C94,Sales^CLead

  • 利用 SELECT  语句将一张表的数据 INSERT 到多个文件中: 
jdbc:hive2://> FROM employee
. . . . . . .> INSERT OVERWRITE DIRECTORY '/user/dayongd/output'
. . . . . . .> SELECT *
. . . . . . .> INSERT OVERWRITE DIRECTORY '/user/dayongd/output1'
. . . . . . .> SELECT * ;
No rows affected (25.4 seconds)

注意:除了使用 Hive 的 Insert 语句, Hive可以通过 HDFS 命令来提取数据到本地或远程,它支持 append  和 overwrite 两种写入方式。 hive -e 'quoted_hql_string'或者 hive -f <hql_filename>命令可以执行一个 Hive 查询语句或者查询文件。Linux 重定向操作符[redirect operators] 和管道可以重定向结果集。一下是一些示例:

  • 键查询结果追加到本地文件: 
    $ hive -e 'select * from employee' >> test
  • 覆盖本地文件: 
    $ hive -e 'select * from employee' > test
  • 追加到 HDFS 文件: 
    $ hive -e 'select * from employee'|hdfs dfs -appendToFile - /user/dayongd/output2/test
  • 覆盖 HDFS 文件: 
    $ hive -e 'select * from employee'|hdfs dfs -put -f - /user/dayongd/output2/test

3. 数据转换 – EXPORT 和 IMPORT

当我们使用 Hive 的时候,有时候需要将数据转移到不同的环境中,或者我们需要备份一部分数据。从 Hive 0.8.0 开始便支持 EXPORT 和 IMPORT 语句来对数据迁移/备份到 HDFS 中。

EXPORT 语句将会从表或分区表中导出数据和元数据。导出的元数据文件被称为 _metadata。导出数据的子目录被称为 data:

jdbc:hive2://> EXPORT TABLE employee TO '/user/dayongd/output3';
No rows affected (0.19 seconds)

After EXPORT, we can manually copy the exported files to other Hive instances or use Hadoop distcp commands to copy to other HDFS clusters. Then, we can import the data in the following manner:

在导出后,我们可以手动复制导出的文件到其他的 Hive 实例中,或者使用 Hadoop distcp 命令将文件拷贝到其他的 Hadoop 集群。目前我们有以下方法导入数据:

  • 将数据从文件导入到一张表中,表名跟文件名相同。如果表存在则会报错: 
jdbc:hive2://> IMPORT FROM '/user/dayongd/output3';
Error: Error while compiling statement: FAILED: SemanticException [Error 10119]: Table exists and contains data files (state=42000,code=10119)
  • 导入到一张新表中: 
jdbc:hive2://> IMPORT TABLE empolyee_imported FROM 
. . . . . . .> '/user/dayongd/output3';
No rows affected (0.788 seconds)
  • 导入到一张外部表中,在这里 LOCATION 属性是可选的: 
jdbc:hive2://> IMPORT EXTERNAL TABLE empolyee_imported_external 
. . . . . . .> FROM '/user/dayongd/output3'
. . . . . . .> LOCATION '/user/dayongd/output4' ;
No rows affected (0.256 seconds)
  • 对分区表进行导出&导入:
jdbc:hive2://> EXPORT TABLE employee_partitioned partition 
. . . . . . .> (year=2014, month=11) TO '/user/dayongd/output5';
No rows affected (0.247 seconds)

jdbc:hive2://> IMPORT TABLE employee_partitioned_imported 
. . . . . . .> FROM '/user/dayongd/output5';
No rows affected (0.14 seconds)

扩展阅读:
有兴趣的同学可以继续参考如下链接的该篇博客,博主翻译了《Programing Hive》中的数据操作 DML: http://flyingdutchman.iteye.com/blog/1868600

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值