本篇文章的讲解结构如下:
一、什么是数据分桶?
二、数据分桶的作用
三、如何创建一个分桶表
四、对分桶表进行的数据抽样
一、什么是数据分桶?
我们都知道,Hive是基于Hadoop的一个数据仓库,可将结构化的数据文件映射为一张数据库表,并提供类SQL查询功能。其实,Hive的本质是将HiveSQL语句转化成MapReduce任务执行。
Hive中,分区提供了一个隔离数据和优化查询的便利方式,不过并非所有的数据都可形成合理的分区,尤其是需要确定合适大小的分区划分方式(有的数据分区数据过大,有的很少,即我们常说的数据倾斜)
我们可以将Hive中的分桶原理理解成MapReduce中的HashPartitioner的原理。都是基于hash值对数据进行分桶。
MR:按照key的hash值除以reduceTask个数进行取余(reduce_id = key.hashcode % reduce.num)
Hive:按照分桶字段(列)的hash值除以分桶的个数进行取余(bucket_id = column.hashcode % bucket.num)
二、数据分桶的作用:
2.1 进行抽样
在处理大规模数据集时,在开发和修改查询的阶段,可以使用整个数据集的一部分进行抽样测试查询、修改。可以使得开发更高效。
2.2 map-side join
获得更高的查询处理效率。桶为表加上了额外的结构,Hive 在处理有些查询时能利用这个结构。具体而言,连接两个在(包含连接列的)相同列上划分了桶的表,可以使用 Map 端连接 (Map-side join)高效的实现。比如JOIN操作。对于JOIN操作两个表有一个相同的列,如果对这两个表都进行了桶操作。那么将保存相同列值的桶进行JOIN操作就可以,可以大大较少JOIN的数据量。
三、创建分桶表:
分桶的实质就是对 分桶的字段做了hash 然后存放到对应文件中,所以说如果原有数据没有按key hash ,需要在插入分桶的时候hash,也就是说向分桶表中插入数据的时候必然要执行一次MAPREDUCE,这也就是分桶表的数据基本只能通过从结果集查询插入的方式进行导入。
3.1 设置Hive的分桶开关
打开Hive客户端,并在会话终端开启Hive分桶的开关:set hive.enforce.bucketing=true;(此设置为临时设置,一旦退出会话终端,再打开就会恢复默认设置false)
此开关打开之后,会自动根据bucket个数自动分配Reduce task的个数,Reduce个数与bucket个数一致。(此外,Reduce的个数还可以通过mapred.reduce.tasks进行设置,但是这方法不推荐在Hive分桶中使用)
3.2 数据源:
-- 将上述8条数据插入中间表test中:
create table test(
id int,
name string,
age int
)
row format delimited
fields terminated by ' '
lines terminated by '\t';
3.3 将数据源加载到中间表test中。
hive> load local inpath '/usr/02hive/data' into table test;
3.4 查看数据:
3.5 建立分桶表(将test表中的数据进行分桶放入分桶表中)
-- 建表语句
create table test_bucket(
id int,
name string,
age int
)
clustered by (age) into 4 buckets
-- 注意分桶字段只能是建表中已有的字段,
-- 而分区表的字段必须是建表中没有的字段
row format delimited
fields terminated by ' ';
3.6 将查询结果返回到分桶表中:
insert into table test_bucket
select id, name, age
from test;
-- 如果使用load加载数据进分桶表,会增加MR的负担
3.7 查看是否分桶成功
如果分桶成功,因为我们创建的是内部表,所以应该在Hive的数据仓库位置下找到test_bucket文件夹(test_bucket表的HDFS存储目录),在该文件夹下应该有4个文件夹(一个bucket一个文件);
Hive的位置默认存储在/usr/hive/warehouse下面:
四、对分桶表进行的数据抽样
-- 语法:
select columns from table tablesample(bucket x out of y on column);
-- x:表示从第几个分桶进行抽样
-- y:表示每隔几个分桶取一个分桶,必须为y的整数倍或者因子
从分桶表的建表语句中可知,我们一共分了4个桶,所以我们这里x取1,y取2:一共抽取2(4/2)个桶,从第一个桶开始,每隔2个桶抽取一次,即第一个桶和第三个桶。
select id,name,age from test_bucket tablesample(bucket 1 out of 2 on age);
结果如图所示:
个人公众号欢迎关注:阿誠的数据杂货铺阿誠的数据杂货铺