【分桶概述】
Hive表 分區的實質是 分目錄(將超大表的數據按指定標准細分到指定目錄),且分區的字段不屬於Hive表中存在的字段; 分桶的實質是 分文件(將超大文件的數據按指定標准細分到分桶文件),且分桶的字段必須在Hive表中存在。
分桶的意義在於:
-
- 可以提高多表join的效率(因為通過分桶已經將超大數據集提取出來了。假如原數據被分了4個桶,此時2表join的時候只需要讀取符合條件的一個分桶,則理論上效率可提升4倍)
- 加速數據抽樣的效率(理由同上,只需要按照指定規則抽取指定分桶的數據即可,不需要掃描全表)
需要Hive表分桶的時候,我們可以觀察到Reduce的任務數量 = 分桶的數量,也就是最終產生的分桶文件的個數,因為分桶表就是通過MapReduce任務計算而來。由此可見,其實桶的概念就是MapReduce的分區的概念,兩者完全相同。
需要注意的是,不論每次插入分桶表的數據量有多少,對應分桶里面是否需要寫入新的數據,Reduce總會啟動分桶數量那么多的task去計算,故可能產生許多空白文件(原因是reduce寫的時候,不知道會不會有數據需要輸出,所以默認初始化了一個文件)。
為了避免產生大量空白文件,給namenode增加無謂的壓力,我們可以通過以下設置方法告知reduce作業不要產生空白文件:
//導入jar包 import org.apache.hadoop.mapreduce.lib.output.LazyOutputFormat; //使用LazyOutputFormat LazyOutputFormat.setOutputFormatClass(job, TextOutputFormat.class);
分桶表取樣語法的核心:
select * from tableName tablesample(bucket x out of y on colum)。其中: x:表示從第x個桶中抽取數據 y:表示每y個桶中抽取一次數據(必須是分桶數量的倍數 or 因子)
假如已經分了6個桶,則:
-
- bucket 2 out of 3 表示:每3個桶中抽取第2個桶中的數據,總共抽取6/3=2次。即:共需要抽取第2、2+3=5號桶共計2個分桶的數據
- bucket 2 out of 6 表示:每6個桶中抽取第2個桶中的數據,總共抽取6/6=1次。即:共需要抽取第2號桶共計1個分桶的數據
- bucket 2 out of 12 表示:每12個桶中抽取第2個桶中的數據,總共抽取6/12=0.5次。即:共需要抽取第2號桶中的一半數據
【用法簡介】
1.開啟支持分桶
set hive.enforce.bucketing=true; -- 默認:false --
設置為 true 之后,mr 運行時會根據 bucket 的個數自動分配 reduce task的個數。
當然,用戶也可以通過 mapred.reduce.tasks 自己設置 reduce 任務個數,但分桶時不推薦使用。注意:一次作業產生的桶(文件數量)和 reduce task 個數一致)
2.往分桶表中加載數據
/* 往分桶表中插入數據的語法類似下面 */ insert into table bucket_table select columns from tbl; -- 全新插入 -- insert overwrite table bucket_table select columns from tbl; -- 覆蓋重寫 --
3.分桶表數據抽樣
/* 抽樣語法:TABLESAMPLE(BUCKET x OUT OF y)。其中: x:表示從第x個桶中抽取數據 y:表示每y個桶中抽取一次數據(必須是分桶數量的倍數 or 因子) */ select * from bucket_table tablesample(bucket 1 out of 4 on columns);
【用法舉例】
1. 假設本地文件 /root/hivedata/ft 中有以下內容:
zhang 12 lisi 34 wange 23 zhouyu 15 guoji 45 xiafen 48 yanggu 78 liuwu 41 zhuto 66 madan 71 sichua 89
2. 新建Hive常規表並導入本地文件:
hive> CREATE TABLE ft( id INT, name STRING, age INT) > ROW FORMAT DELIMITED FIELDS TERMINATED BY'\t'; OK Time taken: 0.216 seconds hive> load data local inpath'/root/hivedata/ft' into table ft; Loading data to table hehe.ft Table hehe.ft stats: [numFiles=1, totalSize=127] OK Time taken: 1.105 seconds hive> select *from ft; OK 1 zhang 12 2 lisi 34 3 wange 23 4 zhouyu 15 5 guoji 45 6 xiafen 48 7 yanggu 78 8 liuwu 41 9 zhuto 66 10 madan 71 11 sichua 89 NULL NULL NULL Time taken: 0.229 seconds, Fetched: 12 row(s)
3. 創建分桶表:
hive> create table fentong( > id int, > name string, > age int,)clustered by(age) into 4 buckets -- 以字段age來划分成4個桶 -- > row format delimited fields terminated by ',';
每行數據具體落入幾號分桶的規則如下:
-
- 用表中指定的字段值(比如age)來除以桶的個數4;
- 結果取余數,也就是求模(若余數為0就放到1號桶,余數為1就放到2號桶,余數為2就放到3號桶,余數為3就放到4號桶)
4. 給分桶表導入數據:
hive> insert into table fentong select name,age from ft;
5. 查詢分桶表數據以確認正確導入:
hive> select * from fentong
6. 我們來看看分桶表的數據如何使用:
hive> select id, name, age from fentong tablesample(bucket 1 out of 4 on age); OK NULL NULL NULL 6 xiafen 48 1 zhang 12 hive> select id, name, age from fentong tablesample(bucket 2 out of 4 on age); OK 11 sichua 89 8 liuwu 41 5 guoji 45 hive> select id, name, age from fentong tablesample(bucket 3 out of 4 on age); OK 9 zhuto 66 7 yanggu 78 2 lisi 34