大数据开发工程师-第八周 第4章 Hive核心实战2


第八周 第4章 Hive核心实战

Hive中的表类型

1
2
3
在Mysql中没有表类型这个概念,因为它就只有一种表。
但是Hive中是有多种表类型的,我们可以分为四种,内部表、外部表、分区表、桶表
下面来一个一个学习一下这些类型的表

内部表

1
2
3
4
5
6
7
8
9
10
首先看内部表
内部表也可以称为受控表
它是Hive中的默认表类型,表数据默认存储在warehouse目录中

在加载数据的过程中,实际数据会被移动到warehouse目录中,就是咱们前面在使用load加载数据的时候,数据就会被加载到warehouse中表对应的目录中
当我们删除表时,表中的数据和元数据将会被同时删除

实际上,我们前面创建的表都属于受控表,前面我们已经演示了,创建一张表,其对应就,在metastore中存储表的元数据信息,当我们一旦从hive中删除一张表之后,表中的数据会被删除,在metastore中存储的元数据信息也会被删除。

这就是内部表的特性。

外部表

1
2
3
4
5
6
7
建表语句中包含External的表叫外部表
外部表在加载数据的时候,实际数据并不会移动到warehouse目录中,只是与外部数据建立一个链接(映射关系)

表的定义和数据的生命周期互相不约束,数据只是表对hdfs上的某一个目录的引用而已,当删除表定义的时候,数据依然是存在的。仅删除表和数据之间引用关系,所以这种表是比较安全的,就算是我们误删表了,数据还是没丢的

我们来创建一张外部表,看一下外部表的建表语句该如何来写
看一下官方文档

image-20230320152938447

image-20230320153023760

image-20230320153157542

image-20230320153244307

1
2
3
4
5
6
7
8
9
10
11
12
13
官网中的案例如下:
主要就是在建表语句中增加了EXTERNAL以及在最后通过locatin指定了这个表数据的存储位置,注意这个路径是hdfs的路径


那根据这个格式我们自己来创建一个外部表
create external table external_table (
key string
) location '/data/external';

表创建完以后到hdfs上查询,如果指定的目录不存在会自动创建
此时到hdfs的/user/hive/warehouse/目录下查看,是看不到这个表的目录的,因为这个表的目录是我们刚才通过location指定的目录

我们再来看一下metastore中的tbls表,这里看到external_table的类型是外部表。

bCVdy9.md.png

1
2
3
4
5
6
7
8
9
10
11
12
13
14
[root@bigdata04 hivedata]# more external_table.data
a
b
c
d
e

加载数据
hive (default)> load data local inpath '/data/soft/hivedata/external_table.dat into table external_table
Loading data to table default.external_table
OK
Time taken: 0.364 seconds

此时加载的数据会存储到hdfs的/data/external目录下

bCZgA0.md.png

1
2
3
接下来尝试删除这个表,看看会发生什么现象
hive (default)> drop table external_table;
到hdfs上查看数据,发现之前上传上去的数据还在

image-20230320153640047

1
这个其实就是前面我们所说的外部表的特性,外部表被删除时,只会删除表的元数据,表中的数据不会被删除。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
在hive中查询目前所有的表信息,发现external_table表确实被删除了
hive (default)> show tables;
OK
tab_name
stu
stu2
stu3
student
t1
t2
t2_bak
t3
t3_new
Time taken: 0.025 seconds, Fetched: 9 row(s)
然后到metastore中查看,发现metastore中的相应的记录也一并被删除掉了

image-20230320153934734

内部表和外部表相互转化

1
2
3
4
5
6
7
8
9
10
11
注意:实际上内外部表是可以互相转化的,需要我们做一下简单的设置即可。
内部表转外部表
alter table tblName set tblproperties (‘external’=‘true’);
外部表转内部表
alter table tblName set tblproperties (‘external’=‘false’);
(不要根据数据是否在warehouse中,来判断是否是内外部表;外部表不指定location时,删除外部表时,warehouse里的数据也不会被删除;内部表也可指指定数据不放到warehouse里,但删除表时,数据还是会被删除)

在实际工作中,我们在hive中创建的表95%以上的都是外部表
因为大致流程是这样的,我们先通过flume采集数据,把数据上传到hdfs中,然后在hive中创建外部表和hdfs上的数据绑定关系,就可以使用sql查询数据了,所以连load数据那一步都可以省略了,因为是先有数据,才创建的表。

画图分析一下。

bCn2Nt.md.png

分区表

单个分区字段

1
2
3
4
5
6
7
8
9
10
11
  假设我们的web服务器每天都产生一个日志数据文件,Flume把数据采集到HDFS中,每一天的数据存储到一个日期目录中。我们如果想查询某一天的数据的话,hive执行的时候默认会对所有文件都扫描一遍,然后再过滤出来我们想要查询的那一天的数据

如果你已经采集了一年的数据,这样每次计算都需要把一年的数据取出来,再过滤出来某一天的数据,效率就太低了,会非常浪费资源,所以我们可以让hive在查询的时候,根据你要查询的日期,直接定位到对应的日期目录。这样就可以直接查询满足条件的数据了,效率提升可不止一点点啊,是质的提升。

想要实现这个功能,就需要使用分区表了

分区可以理解为分类,通过分区把不同类型的数据放到不同目录中
分区的标准就是指定分区字段,分区字段可以有一个或多个,根据咱们刚才举的例子,分区字段就是日期
分区表的意义在于优化查询,查询时尽量利用分区字段,如果不使用分区字段,就会全表扫描,最典型的一个场景就是把天作为分区字段,查询的时候指定天

按照上面的分析,我们来创建一个分区表,使用partitioned by指定区分字段,分区字段的名称为dt,类型为string
1
2
3
4
5
6
7
8
create table partition_1 (
id int,
name string
) partitioned by (dt string)
row format delimited
fields terminated by '\t';

查看表的信息,可以看到分区信息

image-20230320154742474

加载数据时自动创建分区
1
2
3
4
5
6
7
数据格式是这样的
[root@bigdata04 hivedata]# more partition_1.data
1 zhangsan
2 lisi

向分区表中加载数据【注意,在这里添加数据的同时需要指定分区信息】
hive (default)> load data local inpath '/data/soft/hivedata/partition_1.data' into table partition_1 partition(dt='20200101')
1
2
来查看一下hdfs中的信息,刚才创建的分区信息在hdfs中的体现是一个目录。
由于这个分区表属于内部表, 所以目录还在warehouse这个目录中

image-20230320155113146

手动创建分区
1
2
3
4
5
6
当然我也可以手动在表中只创建分区:
hive (default)> alter table partition_1 add partition (dt='2020-01-02');
OK
Time taken: 0.295 seconds

此时会发现hdfs中又多了一个目录,只不过这个分区目录中是没有数据的

bClx0g.md.png

1
2
3
4
5
6
向这个分区中添加数据,可以使用刚才的load命令或者hdfs的put命令都可以

hive (default)> load data local inpath '/data/soft/hivedata/partition_1.data' into table partition_1 partition (dt='2020-01-02');
Loading data to table default.partition_1 partition (dt=2020-01-02)
OK
Time taken: 1.279 seconds

bC1YHe.md.png

查看表的分区
1
2
3
4
5
6
7
8
如何查看我的表中目前有哪些分区呢,语法为: show partitions tblName

hive (default)> show partitions partition_1;
OK
partition
dt=2020-01-01
dt=2020-01-02
Time taken: 0.246 seconds, Fetched: 2 row(s)
删除分区
1
2
3
4
5
6
7
8
9
10
11
12
13
那问题来了,刚才增加了一个分区,那我能删除一个分区吗?
必须是可以的

hive (default)> alter table partition_1 drop partition(dt='2020-01-02');
Dropped the partition dt=2020-01-02
OK
Time taken: 0.771 seconds

hive (default)> show partitions partition_1;
OK
partition
dt=2020-01-01
Time taken: 0.174 seconds, Fetched: 1 row(s)
1
注意了,此时分区删除之后,分区中对应的数据也就没有了,因为是内部表,所以分区的数据是会被删掉的

多个分区字段

1
2
3
4
刚才呢,我们创建了一个分区,但是有的业务需求,需要创建多个分区,可以吗?
当然是可以的!
这里再举一个例子。某学校,有若干二级学院,每年都招很多学生,学校的统计需求大部分会根据年份和学院名称作为条件
所以为了提高后期的统计效率,我们最好是使用年份和学院名称作为分区字段
1
2
3
4
5
6
create table partition_2 (
id int,
name string
) partitioned by (year int, school string)
row format delimited
fields terminated by '\t';
1
2
3
4
5
6
7
8
9
10
11
12
hive (default)> desc partition_2;
OK
col_name data_type comment
id int
name string
year int
school string
# Partition Information
# col_name data_type comment
year int
school string
Time taken: 0.097 seconds, Fetched: 9 row(s)
1
2
3
4
5
数据文件内容
[root@bigdata04 hivedata]# more partition_2.data
1 zhangsan
2 lisi
3 wangwu
1
注意:数据文件中只需要有id和name这两个字段的值就可以了,具体year和school这两个分区字段是在加载分区的时候指定的。
1
2
3
4
5
6
7
hive (default)> load data local inpath '/data/soft/hivedata/partition_2.data' into partition_2 patition(year=2020, school="xk")

hive (default)> load data local inpath '/data/soft/hivedata/partition_2.data' into partition_2 patition(year=2020, school="english")

hive (default)> load data local inpath '/data/soft/hivedata/partition_2.data' into partition_2 patition(year=2019, school="xk")

hive (default)> load data local inpath '/data/soft/hivedata/partition_2.data' into partition_2 patition(year=2019, school="english")
1
2
3
4
5
6
7
8
查看分区信息
hive (default)> show partitions partition_2;
OK
partition
year=2019/school=english
year=2019/school=xk
year=2020/school=english
year=2020/school=xk

查询分区表

1
2
3
4
5
6
前面我们讲了如何创建、增加和删除分区
还有一个比较重要的是我们该如何查询分区中的数据呢?其实非常简单,分区相当于我们的一个查询条件,直接跟在where后面就可以了。

select * from partition_2; 【全表扫描,没有用到分区的特性】
select * from partition_2 where year = 2019;【用到了一个分区字段进行过滤】
select * from partition_2 where year = 2019 and school = 'xk';【用到了两个分区字段进行过滤】
1
2
3
这就是分区表的主要操作

其实我们在这使用的分区表可以认为是内部分区表,内部分区表的应用场景也不多,外部分区表的应用场景才多,外部分区表就是在外部表的基础上又增加了分区。

image-20230320160454144

image-20230320160516832

image-20230320160547061

image-20230320160558709

外部分区表

1
2
3
4
5
6
7
8
9
10
外部分区表示工作中最常用的表
我们先来创建一个外部分区表

create external table ex_par(
id int,
name string
)partitioned by(dt string)
row format delimited
fields terminated by '\t'
location '/data/ex_par';
1
2
3
4
5
6
7
8
9
10
11
其它的操作和前面操作普通分区表是一样的,我们主要演示一下添加分区数据和删除分区的操作

添加分区数据
hive (default)> load data local inpath '/data/soft/hivedata/ex_par.data' into table ex_par partition(dt=20200101)


hive (default)> show partitions ex_par;
OK
partition
dt=2020-01-01
Time taken: 0.415 seconds, Fetched: 1 row(s)
1
2
3
4
5
6
7
8
9
10
删除分区(删除后,此时hdfs上的分区目录还在)
hive (default)> alter table ex_par drop partition(dt='2020-01-01');
Dropped the partition dt=2020-01-01
OK
Time taken: 0.608 seconds

hive (default)> show partitions ex_par;
OK
partition
Time taken: 0.229 seconds
1
2
3
4
5
注意:此时分区目录的数据还是在的,因为这个是外部表,所以删除分区也只是删除分区的定义,分区中的数据还是在的,这个和内部分区表就不一样了

虽然这个分区目录还在,但是刚才我们通过,show partitions已经查不到分区信息了,所以查询表数据是查不出来的,虽然这个目录确实在这个表对应的hdfs目录中,但是由于这个是一个分区表,这份数据没有和任何分区绑定,所以就查询不出来

这个一定要注意,在实际工作中新手最容易遇到的一个问题就是,针对分区表,通过hdfs的put命令把数据上传上去了,但是却查不到数据,就是因为没有在表中添加分区信息,也就是说你们现在虽然在一起了,但是还没有领结婚证,国家还不承认。

image-20230320164050086

1
2
如果数据已经上传上去了,如何给他们绑定关系呢?就是使用前面咱们讲的alter add partition命令,注意在这里需要通过location指定分区目录
hive (default)> alter table ex_par add partition(dt='2020-01-01') location '/data/ex_par/dt=20200101'; (这里不写location后面的也可以)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
此时再查询分区数据和表数据,就正常了。
hive (default)> show partitions ex_par;
OK
partition
dt=2020-01-01
Time taken: 0.19 seconds, Fetched: 1 row(s)

hive (default)> select * from ex_par;
OK
ex_par.id ex_par.name ex_par.dt
1 zhangsan 2020-01-01
2 lisi 2020-01-01
3 wangwu 2020-01-01
Time taken: 0.432 seconds, Fetched: 3 row(s)

总结

1
2
3
4
5
6
7
8
load data local inpath '/data/soft/hivedata/ex_par.data' into table ex_par  partition(dt='20200101');
load data .... partition 这条命令做了两个事情,1:上传数据,2:添加分区(绑定数据和分区之间的关系)

hdfs dfs -mkdir /data/ex_par/20200101
hdfs dfs -put /data/soft/hivedata/ex_par.data /data/ex_par/20200101

alter table ex_par add partition(dt='20200101') location '/data/ex_par/dt=20200101';
上面这三条命令做了两件事情,1:上传数据 2:添加分区(绑定数据和分区之间的关系)
1
外部分区表是工作中最常见的表

经验

1
2
3
4
5
1.在实际工作中,我们在hive中创建的表95%以上的都是外部表
因为大致流程是这样的,我们先通过flume采集数据,把数据上传到hdfs中,然后在hive中创建外部表和hdfs上的数据绑定关系,就可以使用sql查询数据了,所以连load数据那一步都可以省略了,因为是先有数据,才创建的表。

2.如果你已经采集了一年的数据,这样每次计算都需要把一年的数据取出来,再过滤出来某一天的数据,效率就太低了,会非常浪费资源,所以我们可以让hive在查询的时候,根据你要查询的日期,直接定位到对应的日期目录。这样就可以直接查询满足条件的数据了,效率提升可不止一点点啊,是质的提升。
想要实现这个功能,就需要使用分区表了

桶表

1
2
3
4
5
桶表是对数据进行哈希取值,然后放到不同文件中存储
物理上,每个桶就是表(或分区)里的一个文件

什么时候会用到桶表呢?
举个例子,针对中国的人口,主要集中河南、江苏、山东、广东、四川,其他省份就少的多了,你像西藏就三四百万,海南也挺少的,如果使用分区表,我们把省份作为分区字段,数据会集中在某几个分区,其他分区数据就不会很多,那这样对数据存储以及查询不太友好,在计算的时候会出现数据倾斜的问题,计算效率也不高,我们应该相对均匀的存放数据,从源头上解决,这个时候我们就可以采用分桶的概念,也就是使用桶表

创建桶表

1
2
3
4
5
下面来建立一个桶表:
这个表的意思是按照id进行分桶,分成4个桶。
create table bucket_tb(
id int
) clustered by (id) into 4 buckets;
1
2
3
4
5
6
7
8
9
10
11
这个时候往桶中加载数据的时候,就不能使用load data的方式了,而是需要使用其它表中的数据,那么给桶表加载数据的写法就有新的变化了。

类似这样的写法
insert into table … select … from …;

注意,在插入数据之前需要先设置开启桶操作,不然数据无法分到不同的桶里面
其实这里的分桶就是设置reduce任务的数量,因为你分了多少个桶,最终结果就会产生多少个文件,最终结果中文件的数量就和reduce任务的数量是挂钩的

设置完 set hive.enforce.bucketing = true可以自动控制reduce的数量从而适配bucket的个数

hive (default)> set hive.enforce.bucketing=true;
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
初始化一个表,用于向桶表中加载数据
原始数据文件是这样的

[root@bigdata04 hivedata]# more b_source.data
1
2
3
4
5
6
7
8
9
10
11
12
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
hive (default)> create table b_source(id int);
OK
Time taken: 0.262 seconds
hive (default)> load data local inpath '/data/soft/hivedata/b_source.data' into table b_source;

hive (default)> select * from b_source;
OK
b_source.id
1
2
3
4
5
6
7
8
9
10
11
12
Time taken: 0.187 seconds, Fetched: 12 row(s)

向桶表加载数据

1
2
向桶表中加载数据
hive (default)> insert into table bucket_tb select id from b_source where id != NULL;

查看结果

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
hive (default)> select * from bucket_tb;
OK
bucket_tb.id
12
8
4
9
5
1
10
6
2
11
7
3
Time taken: 0.183 seconds, Fetched: 12 row(s)
1
按照我们设置的桶的数量为4,这样在hdfs中会存在4个对应的文件,每个文件的大小是相似的

image-20230320165751106

1
到hdfs上查看桶表中的文件内容,可以看出是通过对buckets取模确定的

bPt0SJ.md.png

1
这样就实现了数据分桶存储。

桶表的作用

数据抽样
1
2
3
4
5
6
7
8
9
10
数据抽样
假如我们使用的是一个大规模的数据集,我们只想去抽取部分数据进行查看.使用bucket表可以变得更加的高效

select * from bucket_tb tablesample(bucket 1 out of 4 on id);
tablesample是抽样语句

语法解析:TABLESAMPLE(BUCKET x OUT OF y ON column)
y尽可能是桶表的bucket数的倍数或者因子,而且y必须要大于等于x
y表示是把桶表中的数据随机分为多少桶(根据column重新分桶,分成4个)
x表示取出第几桶的数据
1
2
3
4
5
6
7
bucket 1 out of 4 on id:根据id对桶表中的数据重新分桶,分成4桶,取出第1桶的数据
bucket 2 out of 4 on id:根据id对桶表中的数据重新分桶,分成4桶,取出第2桶的数据
bucket 3 out of 4 on id:根据id对桶表中的数据重新分桶,分成4桶,取出第3桶的数据
bucket 4 out of 4 on id:根据id对桶表中的数据重新分桶,分成4桶,取出第4桶的数据


验证一下效果,这里面四个SQL语句,每个SQL语句取出一个桶的数据,最终的总和就是表中的所有数据

image-20230320171725720

提高某些查询效率
1
2
3
4
例如:join查询,可以避免产生笛卡尔积的操作
select a.id,a.name,b.addr from a join b on a.id = b.id;

如果a表和b表已经是分桶表,而且分桶的字段是id字段,那么做这个操作的时候就不需要再进行全表笛卡尔积了,因为分桶之后相同规则的id已经在相同的文件里面了。

临时表

1
一般用普通内部表做临时表使用

视图

1
Hive中,也有视图的概念,那我们都知道视图实际上是一张虚拟的表,是对数据的逻辑表示,它的主要作用是为了降低查询的复杂度。
1
2
3
那我们在Hive中如何来创建一个视图呢?
需要使用create view命令,
下面我们来创建一个视图

创建视图

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
hive (default)> create view v1 as select t3_new.id,t3_new.stu_name from t3_new;

此时通过 show tables 也可以查看到这个视图
hive (default)> show tables;
OK
tab_name
b_source
bucket_tb
ex_par
partition_1
partition_2
stu
stu2
stu3
student
t1
t2
t2_bak
t3
t3_new
v1

查询视图

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
查看视图的结构,显示的内容和表显示的内容是没有区别的

hive (default)> desc v1;
OK
col_name data_type comment
id int
stu_name string
Time taken: 0.041 seconds, Fetched: 2 row(s)

通过视图查询数据
hive (default)> select * from v1;
OK
v1.id v1.stu_name
1 张三
2 李四
3 王五
1
2
3
注意:视图在/user/hive/warehouse中是不存在的。因为它只是一个虚拟的表

在元数据metastore中的体现

biY1Tf.md.png

删除视图

1
drop view v1;

综合案例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
接下来我们来看一个综合案例,主要使用外部分区表和视图实现

需求:Flume按天把日志数据采集到HDFS中的对应目录中,使用SQL按天统计每天数据的相关指标

分析一下:
Flume按天把日志数据保存到HDFS中的对应目录中
针对Flume的source可以使用execsource、channel可以使用基于文件的或者内存的,sink使用hdfssink,在hdfssink的path路径中需要使用%Y%m%d获取日期,将每天的日志数据采集到指定的hdfs目录中

这个是我们在前面学习Flume的时候已经讲过的了,这个倒不难

后面就是需要对按天采集的日志数据建表,由于这份数据可能会被多种计算引擎使用,所以建议使用外部表,这样就算我们不小心把表删了,数据也还是在的,不影响其他人使用,还有就是这份数据是按天分目录存储的,在实际工作中,离线计算的需求大部分都是按天计算的,所以在这里最好在表中增加日期这个分区字段,所以最终决定使用外部分区表。

前面FLume采集数据的流程我们就不再演示了,在这我就直接使用之前我们使用hdfs落盘的数据了。

我们之前有一个案例是分类型,分目录,把多种类型的数据存储到不同的目录下

目录结构是这样的,首先是按天,然后是按照类型

![image-20230320175120995](D:\GitHub\myblog\source_posts\大数据开发工程师-第八周-第4章-Hive核心实战 3-表类型\image-20230320175120995.png)

1
这里面的数据是json格式的,也是有规律的,如果我们在建表的时候该怎么创建?

image-20230320175214506

1
2
3
4
5
6
7
针对json格式的数据建表的时候没办法直接把每个字段都定义出来

通常的解决方案是先写一个mapreduce数据清洗任务,只需要map阶段就行了,对json格式的数据进行解析,把里面每个字段的值全部解析出来,拼成一行,字段值中间可以使用逗号分割,然后再基于解析之后的数据在hive中建表就可以了。

这个解决方案没有任何问题,如果硬要挑问题,那就只能鸡蛋里面挑骨头,说这个解决方案比较麻烦,还需要写MapReduce,不够优雅了。

我们开发人员有时候一定要懒,这个懒不是说什么都不敢,而是要想办法把复杂的问题简单化,这个懒可以督促你去找出最方便快捷的解决方案。
1
2
3
4
5
6
在这里我们需要提前涉及一个函数get_json_object,这个函数可以从json格式的数据中解析出指定字段
所以我的思路是这样的,先基于原始的json数据创建一个外部分区表,表中只有一个字段,保存原始的json字符串即可,分区字段是日期和数据类型

然后再创建一个视图,视图中实现的功能就是查询前面创建的外部分区表,在查询的时候会解析json数据中的字段

这样就方便了,我们以后查询直接查视图就可以查询出我们需要的字段信息了,并且一行代码都不需要写。

建表

1
2
3
4
5
6
create external table ex_par_more_type(
log string
)partitioned by(dt string,d_type string)
row format delimited
fields terminated by '\t'
location '/moreType';
1
2
3
加载数据 【注意,此时的数据已经通过flume采集到hdfs中了,所以不需要使用load命令了,只需要使用一个alter命令添加分区信息就可以了,但是记得要把那三个子目录都添加进去】

添加分区 【注意,这个步骤每天都要做一次】

image-20230320211922659

1
可以先查询一下数据,可以查询出来,说明前面的配置没有问题。

image-20230320214504086

创建视图

1
2
3
4
5
接下来就是重点了,需要创建视图,在创建视图的时候从数据中查询需要的字段信息
注意了,由于这三种类型的数据字段是不一样的,所以创建一个视图还搞不定,只能针对每一种类型创建一个视图。
如果这三种类型的数据字段都是一样的,就可以只创建一个视图了。

注意:由于字段数量太多,在这里针对每个每种数据只获取里面的前4个字段
1
giftRecord类型的视图

image-20230320212834028

1
userInfo类型的视图

image-20230320213408763

image-20230320213529350

1
videoInfo类型的视图

image-20230320213447601

image-20230320213550522

1
注意:此时在SQL后面加不加日期都是一样的,因为现在只有这一天的数据

创建定时器

1
2
3
4
5
6
后面想要查询数据就直接通过视图,指定日期查询就可以了,不指定日期的话会查询这个类型下面所有的数据。
其实到这里还没完,因为后期flume每天都会采集新的数据上传到hdfs上面,所以我们需要每天都做一次

添加分区的操作。
这个操作肯定是要写到脚本中定时调度的,否则每天手工执行还不疯了
开发脚本,脚本名称为 addPartition.sh
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
[root@bigdata04 hivedata]# vi addPartition.sh
#!/bin/bash
# 每天凌晨1点定时添加当天日期的分区
if [ "a$1" = "a" ]
then
dt=`date +%Y%m%d`
else
dt=$1
fi
# 指定添加分区操作
hive -e "
alter table ex_par_more_type add partition(dt='${dt}',d_type='giftRecord') location '/moreType/${dt}/giftRecord';
alter table ex_par_more_type add partition(dt='${dt}',d_type='userInfo') location '/moreType/${dt}/userInfo';
alter table ex_par_more_type add partition(dt='${dt}',d_type='videoInfo') location '/moreType/${dt}/videoInfo';
"

image-20230320215040572

image-20230320215354733

1
2
3
不指定if not exists时,当存在分区时会报错

可以将已有的分区删除了,再创建分区

image-20230320215740484

1
2
3
加-x 更清晰

因为获取的是当天时间,hdfs上现在没有,所以用了下面的手动传参

image-20230320215911090

image-20230320220121268

1
配置crontab

image-20230320220256889

1
2
3
4
5
这就是一个完整的开发流程,针对需要多次执行的sql一般都是需要配置到脚本中使用hive -e去执行的。
最后再来分析一下,针对这个需求如果数据量不算太打,并且大家对计算效率要求也不算太高的话是没有问题的。
因为现在这种逻辑是每次在查询视图的时候会对原始数据进行解析再计算,如果每天的数据量达到几百G,甚至上T的时候,查询效率就有点低了,大致需要10~20分钟左右,每次查询都是这样,不管你查询多少次,,每次都要根据原始数据进行解析。
如果感觉这个时间不能接受,想要优化,那只能从源头进行优化了,就是先对原始的json数据进行清洗,把需要的字段解析出来,存储到hdfs中,再建表,这个时候就可以提高效率了,因为对原始数据解析的过程只需要一次,后期计算的时候都是对解析过的数据直接计算了,省略了解析步骤,效率可以提升一倍以上。
所以这个就要综合实际情况去考虑了,选便捷性还是选效率

本文标题:大数据开发工程师-第八周 第4章 Hive核心实战2

文章作者:TTYONG

发布时间:2022年02月20日 - 12:02

最后更新:2023年06月16日 - 19:06

原始链接:http://tianyong.fun/%E5%A4%A7%E6%95%B0%E6%8D%AE%E5%BC%80%E5%8F%91%E5%B7%A5%E7%A8%8B%E5%B8%88-%E7%AC%AC%E5%85%AB%E5%91%A8-%E7%AC%AC4%E7%AB%A0-Hive%E6%A0%B8%E5%BF%83%E5%AE%9E%E6%88%98%203-%E8%A1%A8%E7%B1%BB%E5%9E%8B.html

许可协议: 转载请保留原文链接及作者。

多少都是爱
0%