不要再使用Load方式加载数据到Hive了,这种方式很low,你造吗?

目录

0 前言

1 采用Load 方式

2 方式2:采用ALTER TABLE更新分区、添加元数据形式(推荐)

3 方式3:利用构建外部表+ msck repair table修复元数据形式加载数据(强烈推荐)

4 小结


0 前言

一般很多企业加载HDFS数据到hive时采用load命令,包括很多文章也推荐该命令形式,但是这种命令并不是一种很好的方式,因为他的本质是剪切数据到Hive里面,这样数据其实是不安全的,而且load的时候很耗时间。其实我们在加载数据的时候,还有更高效,更便捷的加载方式,本文重点对这几种方式进行总结对比分析。

1 采用Load 方式

(1)命令

LOAD DATA [LOCAL] INPATH 'filepath' [OVERWRITE] INTO TABLE tablename partition (A='XXX')

(2)解释

[LOCAL]可选项,
带LOCAL表示从你的本地(指linux服务器上)加载文件到HIVE表内容里面,Local本地上面对应的这个文件不会消失.
不带LOCAL标识,表示从HDFS上面文件移动到HIVE表里面,HDFS路径下对应的该文件就会消失。实际上就是剪切

不管是否带有LOCAL标识,其实本质上面都是把这个文件加载到Hive表对应的HDFS路径下.直接把这个文件使用hdfs dfs -mv或者hdfs dfs -put到Hive表对应的路径下效果是一样的.只不过使用Load方式加载必须是在Hive的命令行界面操作(HIVE内部命令)。

注意点:带Local肯定比不带Local效率低。

  • Local模式:本地(Linux)->Hdfs->mv 到Hive路径文件夹
  • 非Local模式:Hdfs->mv 到Hive路径文件夹,效率大概是5倍关系

[OVERWRITE]可选项

load data inpath ‘/department’ OVERWRITE into table deptpart partition(area=‘beijing’);

表示插入数据是否会覆盖之前的数据,加上overwrite就会覆盖之前数据,不加上是在之前数据基础上执行追加。

上面我们能够了解到,其实所谓的Hive表的数据,就可以理解成这个表对应的在Hdfs路径下的数据文件。但是如果要是外部表(External)呢,因为外部表相当于是一个壳子,我们在删除外部表(drop table)时候,只是把外部表这个壳子删除了,你就可以理解成外部表没有权限删除对应的Hdfs上面的数据,但是在使用overwirte into external table,他会把Hdfs上面的数据覆盖到,从这里更可以看出,Load的权限更高,Load底层就是直接靠直接操作表对应Hdfs上面的文件夹下的文件来实现的

总结:通过对load命令的回顾复习,我们理解到hive本质是构建在HDFS基础上的,实质还是对HDFS文件的管理,所谓的表其实是对HDFS底层目录数据文件进行的映射,那么我们可以理解hive表数据加载同步实质上也就是底层HDFS数据文件的移动。有了上述的理解,我们就可以更好得出方式2和方式3.


2 方式2:采用ALTER TABLE更新分区、添加元数据形式(推荐)
 

这种形式数据更安全,不会被剪切掉,只是通过alter table语句更新新分区、添加元数据。

具体我们以如下示例给出

	drop table if exists test;
	CREATE EXTERNAL TABLE test(
		message string
	)
	PARTITIONED BY (dt string)
	LOCATION '/user/hive/warehouse/ods/test';

 加载数据

	ALTER TABLE test ADD IF NOT EXISTS PARTITION (dt='20220625') LOCATION '/data/log/20220625';


上述命令中注意通过loation来指定分区表数据的位置,location后面跟的是HDFS数据位置,HDFS上的数据也是按天作为分区目录的。

如果需要动态更新可以借助shell脚本实现,如下

#!/bin/bash
lastday=`date --date '-1days' +%Y%m%d` #获得昨天的日期
if [ "$1" != "" ];then
  lastday=$1
fi;
source ./config.properties
sql="
	ALTER TABLE test ADD IF NOT EXISTS PARTITION (dt='${lastday}') LOCATION '/data/logs/${lastday}';
"
${beeline} -u ${remote_host}/${database} -e "$sql"


3 方式3:利用构建外部表+ msck repair table修复元数据形式加载数据(强烈推荐)

这种方式通过构建外表,不仅保证了数据安全性,同时也能达到同步数据的目的,比如构建一张日志表,每天都有上游用户写入日志到HDFS目录。

情景1:如果日志目录没有分区目录,需要全量加载。

这种情况,可以直接建立外部表,指定表路径到HDFS数据位置即可。建表如下

	CREATE EXTERNAL TABLE test(
		message string
	)
	PARTITIONED BY (dt string)
	LOCATION '/data/logs';

通过location指定数据文件的位置,在方式一中讲到了HIVE表本质就是把这个表的数据放在该表对应的HDFS路径下,其中location就是指定数据文件位置的,我们可以直接指定其位置在已知的HDFS路径下。

情景2:日志目录(HDFS)有分区,hive表为分区表


对于大多数日志场景其实应该是对应这种情况,面对有分区目录,hive为分区表时,应该怎么做呢?可以有两种思路,一种利用方式2通过Alter table方式添加元数据形式加载分区数据,另一种可以利用修复分区命令,修复元数据形式达到加载数据的目的,这里我们重点讲修复分区的方式。

步骤1:构建外部表(注意此时location指定的目录为HDFS上分区目录的父目录)

如HDFS日志文件目录如下
 

/data/logs/dt=20220622

/data/logs/dt=20220623

/data/logs/dt=20220624

/data/logs/dt=20220625

建立外部 表时,指定location的位置为其父目录 /data/logs

	CREATE EXTERNAL TABLE test(
		message string
	)
	PARTITIONED BY (dt string)
	LOCATION '/data/logs';

这一步可以理解为上传数据到hive表分区目录

步骤2:利用msck repair table命令修复元数据

msck repair ods.test

此时会看到表中数据被同步过来,并且分区字段有值。

这一步可以理解为告诉管理员我的目录文件发生了变化,需要同步信息,建立联系。

这种方式的优势:

(1)可以将历史数据全部同步过来,而不需要手动一张张添加分区,即使上游更改历史数据,或数据发生变动也能全部同步进来.

(2)性能相较于前面几种方式更优,基本上不耗时,还保证了数据安全性

注意点:

(1)HDFS分区目录的要求和hive分区表目录一致的,不然是不会识别的,这就要求上游传输数据的时候分区目录必须按照如本案例中dt=20220625这种形式上传。也就是说你必须按照hive分区表的HDFS文件目录上传数据文件

(2)如果上游不按规则来,存在无法识别的分区目录会报如下错误

FAILED: Execution Error, return code 1 from org.apache.hadoop.hive.ql.exec.DDLTask

解决办法:设置如下参数,设置无效路径为ignore

set hive.msck.path.validation=ignore;
先使用上述命令后,再执行:msck repair table 库名.表名。

4 小结

本文对hive中几种常见加载数据方式进行了总结,通过几种方式的对比,一种比一种更有效高效。通过更新分区添加元数据及修复分区的这两种方式,其视野更高,看的更远,是站在运维角度以及对hive底层数据形式更高级的理解角度来分析,属于高级层次的命令形式。

猜你喜欢

转载自blog.csdn.net/godlovedaniel/article/details/125464274