Hive把表组织成分区(partition)。这是一种根据分区列(partition column,如日期)的值对表进行粗略的划分机制。使用分区可以加快数据分片(slice)的查询速度。
表或分区可以进一步划分为桶(bucket)。它会为数据提供额外的结构以获取更高效的查询处理。例如,通过根据用户ID来划分桶,我们可以在所有用户集合的随机样本上快速计算基于用户的查询。
分桶适用场景:
数据抽样( sampling )、map-join
- 创建分区表
hive> CREATE TABLE pt1(id INT,name STRING,hobby ARRAY,address MAP)
> PARTITIONED BY(dt STRING,country STRING)
> ROW FORMAT DELIMITED FIELDS TERMINATED BY ','
> COLLECTION ITEMS TERMINATED BY '-'
> MAP KEYS TERMINATED BY ':';
OK
Time taken: 0.196 seconds
hive> show tables;
OK
pt1
Time taken: 0.063 seconds, Fetched: 1 row(s)
说明:我们可以看到创建分区表和之前创建表的唯一区别就是多了Partitioned By,如果要创建一个分区那么里面就写一个字段、我们这里演示的是创建多个(两个)分区。
在WEB UI中查看
查看一下表格式:
hive> desc formatted pt1;
OK
# col_name data_type comment
id int
name string
hobby array
address map
# Partition Information
# col_name data_type comment
dt string
country string
# Detailed Table Information
Database: htest
Owner: root
CreateTime: Sat Aug 04 15:16:34 CST 2018
LastAccessTime: UNKNOWN
Protect Mode: None
Retention: 0
Location: hdfs://mycluster/user/hive/warehouse/htest.db/pt1
Table Type: MANAGED_TABLE
Table Parameters:
transient_lastDdlTime 1533366994
# Storage Information
SerDe Library: org.apache.hadoop.hive.serde2.lazy.LazySimpleSerDe
InputFormat: org.apache.hadoop.mapred.TextInputFormat
OutputFormat: org.apache.hadoop.hive.ql.io.HiveIgnoreKeyTextOutputFormat
Compressed: No
Num Buckets: -1
Bucket Columns: []
Sort Columns: []
Storage Desc Params:
colelction.delim -
field.delim ,
mapkey.delim :
serialization.format ,
Time taken: 0.178 seconds, Fetched: 38 row(s)
可以看到分区信息中多了两个分区字段
加载数据:
- 准备数据
id,name,hobby,address
1,张三,篮球-足球-音乐,北京:上海
2,李四,看书-旅游-爬山,西安:成都
3,王五,钢琴-小提琴-古筝,重庆:杭州
4,赵六,抽烟-喝酒-烫头发,哈尔滨:沈阳
2.加载数据
hive> LOAD DATA LOCAL INPATH '/root/data/hdata1' into table pt1;
FAILED: SemanticException [Error 10062]: Need to specify partition columns because the destination table is partitioned
如果还和之前一样加载数据,显然直接报错,根据错误日志很明显看出,给分区表加载数据必须要指定分区列。
hive> LOAD DATA LOCAL INPATH '/root/data/hdata1' into table pt1
PARTITION(dt='2018-08-04',country='CHINA');
Loading data to table htest.pt1 partition (dt=2018-08-04, country=CHINA)
Partition htest.pt1{dt=2018-08-04, country=CHINA} stats: [numFiles=1, numRows=0, totalSize=207, rawDataSize=0]
OK
Time taken: 1.091 seconds
说明:我这次加载数据的时候把分区的日期字段定义为dt='2018-08-04',国家字段定义为country=’CHINA’,那么这一批数据都属于这个两个分区;如果明天我要加载第二批数据的时候,那么就把日期字段和国家字段进行相应的修改,这样就可以很完美的把数据进行分区了。
查看一下表中是数据:
hive> select * from pt1;
OK
NULL name ["hobby"] {"address":null} 2018-08-04 CHINA
1 张三 ["篮球","足球","音乐"] {"北京":"上海"} 2018-08-04 CHINA
2 李四 ["看书","旅游","爬山"] {"西安":"成都"} 2018-08-04 CHINA
3 王五 ["钢琴","小提琴","古筝"] {"重庆":"杭州"} 2018-08-04 CHINA
4 赵六 ["抽烟","喝酒","烫头发"] {"哈尔滨":"沈阳"} 2018-08-04 CHINA
Time taken: 0.157 seconds, Fetched: 5 row(s)
在WEB UI中查看,也能看到数据存在两个分区列目录中:
- 创建分桶表
hive> CREATE TABLE bt1(id INT,name STRING,hobby ARRAY,address MAP)
> CLUSTERED BY(id) INTO 4 BUCKETS
> ROW FORMAT DELIMITED FIELDS TERMINATED BY ','
> COLLECTION ITEMS TERMINATED BY '-'
> MAP KEYS TERMINATED BY ':';
OK
Time taken: 0.161 seconds
说明:分桶表是对列值取哈希值的方式,将不同数据放到不同文件中存储。
对于hive中每一个表、分区都可以进一步进行分桶。
由列的哈希值除以桶的个数来决定每条数据划分在哪个桶中。
2.加载数据
(1)前提:
开启支持分桶
set hive.enforce.bucketing=true;
默认:false;设置为true之后,mr运行时会根据bucket的个数自动分配reduce task个数。(用户也可以通过mapred.reduce.tasks自己设置reduce任务个数,但分桶时不推荐使用)
注意:一次作业产生的桶(文件数量)和reduce task个数一致。
(2)分桶加载数据和分区以及表的方式不一样,不能使用LOAD,加载数据的方式有两种:
insert into table bt1 select columns from pt1;
insert overwrite table bt1 select columns from pt1;
这里我使用第二种:(把上面创建的分区表的数据导入这个分通表)
INSERT OVERWRITE TABLE bt1 SELECT id,name,hobby,address from pt1;
导入数据后查看WEB UI:
可以看到的确分了四个桶,每个桶对应一个文件
查看这四个文件:
[root@unisk01 ~]# hadoop fs -cat /user/hive/warehouse/htest.db/bt1/000000_1000
4,赵六,抽烟-喝酒-烫头发,哈尔滨:沈阳
[root@unisk01 ~]# hadoop fs -cat /user/hive/warehouse/htest.db/bt1/000001_1001
1,张三,篮球-足球-音乐,北京:上海
[root@unisk01 ~]# hadoop fs -cat /user/hive/warehouse/htest.db/bt1/000002_1000
2,李四,看书-旅游-爬山,西安:成都
[root@unisk01 ~]# hadoop fs -cat /user/hive/warehouse/htest.db/bt1/000003_1000
3,王五,钢琴-小提琴-古筝,重庆:杭州
[root@unisk01 ~]#