Hive 分桶详解

2018-12-24  本文已影响0人  博弈史密斯

1分桶

1.1什么是分桶?和分区有什么区别?

分区:Hive在查询数据的时候,一般会扫描整个表的数据,会消耗很多不必要的时间。有些时候,我们只需要关心一部分数据,比如WHERE子句的查询条件,那这时候这种全表扫描的方式是很影响性能的。从而引入了分区的概念。分区就是对数据进行分类,这样在查询的时候,就可以只是针对分区查询,从而不必全表扫描。

一个目录对应一个分区

分桶:并非所有的数据集都可形成合理的分区,特别之前所提到过的要确定合适的划分大小的疑虑。对于每一个表或者分区,可以进一步细分成桶,桶是对数据进行更细粒度的划分。Hive默认采用对某一列的每个数据进行hash(哈希),使用hashcode对 桶的个数求余,确定该条记录放入哪个桶中。

分桶实际上和 MapReduce中的分区是一样的。分桶数和reduce数对应。

一个文件对应一个分桶

1.2如何创建一个分桶?

1.2.1 语法格式

CREATE [EXTERNAL] TABLE <table_name>

(<col_name> <data_type> [, <col_name> <data_type> ...])]

[PARTITIONED BY ...]

CLUSTERED BY (<col_name>)

[SORTED BY (<col_name> [ASC|DESC] [, <col_name> [ASC|DESC]...])]

INTO <num_buckets> BUCKETS

具体解释:

只能对一列进行分桶。表可以同时分区和分桶,当表分区时,每个分区下都会有<num_buckets> 个桶。当使用 SORTED BY … 在桶内排序时,指定排序的列和指定分桶的列无需相同。ASC 为升序选项,DESC 为降序选项,默认排序方式是升序。<num_buckets> 指定分桶个数,也就是表目录下小文件的个数。

1.2.2 创建分桶实例

(1)创建一个student表:

hive> create table student(

st_id int,

st_name string,

st_sex string,

st_age int,

st_dept string

)

clustered by(st_dept) sorted by(st_age desc) into 3 buckets

row format delimited fields terminated by ',';

//  sorted by可以省略

(2)查看表结构:

hive> desc formatted student;

Num Buckets:            3  

导入数据有两种,一种是通过文件导入,但是并不会真正的分桶 ;一种是通过从其他表插入的方式导入数据,这种方式才能真正的分桶;

(3)建一个普通的student1表

hive> create table student1(st_id int,st_name string,st_sex string,st_age int,

> st_dept string)  row format delimited fields terminated by ',';

(4)导入数据到student1表

hive> load data local inpath '/hive/student.txt' into table student1;

(5)导入数据到分桶的表

方法一:

<pre>//打开强制分桶开关:</pre>

hive (myhive)> set hive.enforce.bucketing=true;

//设置reduces数为-1:

hive (myhive)> set mapreduce.job.reduces=-1;

//通过其他表插入数据

hive (myhive)> insert into table student select id, name from stu ;

(通过这种方法,得到的分桶对应的文件,数据是无序的,也就是 sorted by 或 sort by无效)

如果没有设置 bucketing属性,我们需要自己设置和分桶个数相匹配的reducer个数。

方法二:

//关闭强制分桶开关:

hive (myhive)> set hive.enforce.bucketing=false;

//设置reduces数和分桶数一致:

hive (myhive)> set mapreduce.job.reduces=3;

//通过其他表插入数据,要添加 distribute by 以及 sort by。

hive (myhive)> insert into table student select id, name from stu distribute by st_dept;

注意:hive.enforce.bucketing为true时,reduce要设为-1;

hive.enforce.bucketing为false时,reduce要设为和分桶数一致;

如果bucketing为 true,reduce又设成大于1的输,会执行两个job。

(为什么通过 load data 的方式导入数据到 student表,并不会分桶?

load data只是把文件上传到 表所在的HDFS目录下。并没有做其他操作。)

总结:我们发现其实桶的概念就是MapReduce的分区的概念,两者完全相同。物理上每个桶就是目录里的一个文件,一个作业产生的桶(输出文件)数量和reduce任务个数相同。

而分区表的概念,则是新的概念。分区代表了数据的仓库,也就是文件夹目录。每个文件夹下面可以放不同的数据文件。通过文件夹可以查询里面存放的文件。但文件夹本身和数据的内容毫无关系。

桶则是按照数据内容的某个值进行分桶,把一个大文件散列称为一个个小文件。这些小文件可以单独排序。如果另外一个表也按照同样的规则分成了一个个小文件。

分桶的好处:

1、两个表join的时候,就不必要扫描整个表,只需要匹配相同分桶的数据即可。效率当然大大提升。

2、同样,对数据抽样的时候,也不需要扫描整个文件。只需要对每个分区按照相同规则抽取一部分数据即可。

2 分桶抽样查询

对于非常大的数据集,有时用户需要使用的是一个具有代表性的查询结果而不是全部结果。Hive可以通过对表进行抽样来满足这个需求。

查询表stu_buck中的数据。

hive (myhive)> select * from student tablesample(bucket 1 out of 3 on id);

注:tablesample是抽样语句,语法:TABLESAMPLE(BUCKET x OUT OF y) 。

y必须是table总bucket数的倍数或者因子。hive根据y的大小,决定抽样的比例。例如,table总共分了4份,当y=2时,抽取(4/2=)2个bucket的数据,当y=8时,抽取(4/8=)1/2个bucket的数据。

x表示从哪个bucket开始抽取,如果需要取多个分区,以后的分区号为当前分区号加上y。例如,table总bucket数为4,tablesample(bucket 1 out of 2),表示总共抽取(4/2=)2个bucket的数据,抽取第1(x)个和第3(x+y)个bucket的数据。

注意:x的值必须小于等于y的值,否则

FAILED: SemanticException [Error 10061]: Numerator should not be bigger than denominator in sample clause for table stu_buck

数据块抽样

Hive提供了另外一种按照百分比进行抽样的方式,这种是基于行数的,按照输入路径下的数据块百分比进行的抽样。


hive (myhive)> select * from student tablesample(0.1 percent) ;

提示:这种抽样方式不一定适用于所有的文件格式。另外,这种抽样的最小抽样单元是一个HDFS数据块。因此,如果表的数据大小小于普通的块大小128M的话,那么将会返回所有行。

喜欢的朋友可以关注下公众号:圳鹏科技

上一篇 下一篇

猜你喜欢

热点阅读