一文彻底学会hive分桶表(实战详解)
本文目录
一、分桶表概述
1.1、什么是分桶表?
分桶是将数据集分解成更容易管理的若*分的一个技术,是比表或分区更为细粒度的数据范围划分。针对某一列进行桶的组织,对列值哈希,然后除以桶的个数求余,决定将该条记录存放到哪个桶中。
常用于:
- 获得更高的查询处理效率
- 抽样调查
1.2、分桶表和分区表有啥区别?
分区表提供了一个隔离数据和优化查询的便利方式。但是在实际场景下,并非所有的数据集都可形成合理的分区。对于一张表或者分区,Hive还可以进一步组织成桶,也就是更为细粒度的数据范围划分。
小结一波:
- 分桶对数据的处理比分区更加细粒度化;
- 分桶和分区两者不干扰,可以把分区表进一步分桶;
- 分区针对的是数据的存储路径;分桶针对的是数据文件。
二、分桶表实战
首先说明一下,我的hive环境是基于docker-compose构建,使用postgresql管理metastore,各重要组件版本如下:
hadoop:2.7.4
hive:2.3.2
java:1.8
其实环境不重要,不用花太多时间,主要还是技术部分,接下来就开始实战吧。
2.1、创建一个分桶表
我们创建一个简单的分桶表,只有两个字段(id,name),并且按照id进行分6个桶,sql如下:
create table test_buck(id int, name string)
clustered by(id)
into 6 buckets
row format delimited fields terminated by '\t';
执行并查看表结构:
使用desc formatted test_buck;
查看test_buck表结构,数据较多,这里截取重要数据如下:
2.2、准备数据
准备一些编号和字符串并按照 "\t"分隔开,把这些数据放入/tools/目录下的test_buck.txt文件内,数据格式如下图:
2.3、向分桶表导入数据
2.3.1、错误导入示范(引出分桶的本质)
数据准备好之后,我们就可以向分桶表里导入数据里。这里我首先使用如下常规命令导入:
load data local inpath '/tools/test_buck.txt' into table test_buck;
然后很惊奇的是它报错了,报错信息如下:
简单翻译一下,报错信息是这样说的:请把数据导入到一个中间表,并使用insert … select语句导入到分桶表里。如果你非要直接导入分桶表里,需要把hive.strict.checks.bucketing设置为false(关闭严格模式),然后你写sql就没有检查了。。。。。
哈哈,到这里,我们知道了分桶表应该怎么导入数据了,但是为啥直接导入就不行呢?下面让我们硬着头皮改为false,然后导入数据试一下。
set hive.strict.checks.bucketing = false;
然后我们打开50070查看hdfs上数据如下:
说好的分6个桶呢?为什么只有一个呢?
这是因为:
桶的概念就是MapReduce的分区的概念,两者是完全一样的。也就是说物理上每个桶就是目录里的一个文件,一个作业产生的桶(输出文件)数量和reduce任务个数相同
所以这里我们导入一个文件,由于分区数等于文件数,只有一个分区,所以上面的操作并没有分桶。
2.3.2、正确导入示范(引出分桶规则)
绕了一圈,感觉还是把hive.strict.checks.bucketing设置为true比较好,节省犯错成本(不过有时候多犯错也是好事,比如上面咱们至少知道了hive分桶本质上就是mapreduce的分区)。
把hive严格模式打开,并把桶表清空:
set hive.strict.checks.bucketing = true;
truncate table test_buck;
下面我们使用之前严格模式下建议我们使用的分桶表导入数据方式,使用中间表来进行数据导入:
-
设置强制分桶为true,并设置reduce数量为分桶的数量个数。
set hive.enforce.bucketing = true;
-
创建一个临时表,并导入数据。
create table temp_buck(id int, name string) row format delimited fields terminated by '\t'; load data local inpath '/tools/test_buck.txt' into table temp_buck;
-
使用insert select来间接把数据导入到分桶表。
insert into table test_buck select id, name from temp_buck;
-
在50070上查看分桶表的数据,已经分为了6个,桶表数据插入成功!
-
查询分桶表里的数据。
select * from test_buck;
结果如下图,仔细观察:
通过观察规则和桶数的对应关系,我们可以得出如下分桶规则:
- Hive的分桶采用对分桶字段的值进行哈希,然后除以桶的个数求余的方式决定该条记录存放在哪个桶当中
2.4、分桶抽样
对表分桶一般有两个目的,提高数据查询效率、抽样调查。通过前面的实战,我们已经可以对分桶表进行正常的创建并导入数据了。一般在实际生产中,对于非常大的数据集,有时用户需要使用的是一个具有代表性的查询结果而不是全部结果。这个时候Hive就可以通过对表进行抽样来满足这个需求。
抽样语句语法解析:
tablesample(bucket x out of y)
y必须是table总bucket数的倍数或者因子。hive根据y的大小,决定抽样的比例。
例如,table总共分了6份,当y=2时,抽取(6/2=)3个bucket的数据,当y=8时,抽取(6/8=)3/4个bucket的数据。
x表示从哪个bucket开始抽取,如果需要取多个分区,以后的分区号为当前分区号加上y。
例如,table总bucket数为6,tablesample(bucket 1 out of 2),表示总共抽取(6/2=)3个bucket的数据,抽取第1(x)个和第3(x+y)个和第5(x+y)个bucket的数据。
注意:x的值必须小于等于y的值
举例:
select * from test_buck tablesample(bucket 1 out of 3 on id);
结果如下图,可以发现,上面这条sql查出了第1个和第4个桶的数据:
三、总结
3.1、分桶表的优点
- 查询效率更快,因为分桶为表加上了额外结构,链接相同列划分了桶的表,可以使用map-side join更加高效;
- 由于分桶规则保证了数据在不同桶的随机性,因此平时进行抽样调查时取样更加方便。
3.2、常用操作
-
建表语句及含义
create table buck_table_name (id int,name string) clustered by (id) sorted by (id asc) into 4 buckets row format delimited fields terminated by '\t'; 注意:CLUSTERED BY来指定划分桶所用列和划分桶的个数。 分桶规则:HIVE对key的hash值除bucket个数取余数,保证数据均匀随机分布在所有bucket里。 SORTED BY对桶中的一个或多个列另外排序
-
导入数据
先把数据导入中间表,然后使用insert select语句进行间接导入到分桶表,比如咱们实战的例子:
insert into table test_buck select id, name from temp_buck;
3.3、分桶表的实质及与分区表的区别
hive的桶其实就是MapReduce的分区的概念,两者完全相同。在物理上每个桶就是目录里的一个文件,一个作业产生的桶(输出文件)数量和reduce任务个数相同。
而分区代表了数据的仓库,也就是文件夹目录。每个文件夹下面可以放不同的数据文件。通过文件夹可以查询里面存放的文件。但文件夹本身和数据的内容毫无关系。
桶则是按照数据内容的某个值进行分桶,把一个大文件散列称为一个个小文件。这些小文件可以单独排序。如果另外一个表也按照同样的规则分成了一个个小文件。两个表join的时候,就不必要扫描整个表,只需要匹配相同分桶的数据即可,效率当然大大提升。
同样的道理,在对数据抽样的时候,也不需要扫描整个文件。只需要对每个分区按照相同规则抽取一部分数据即可。
上一篇: javascript设计模式 – 建造者模式原理与应用实例分析
下一篇: 初体验hive创建映射
推荐阅读