Hive分区和桶的概念
Hive?已是目前業界最為通用、廉價的構建大數據時代數據倉庫的解決方案了,雖然也有 Impala 等后起之秀,但目前從功能、穩定性等方面來說,Hive 的地位尚不可撼動。
其實這篇博文主要是想聊聊 SMB join 的,Join 是整個 MR/Hive 最為核心的部分之一,是每個Hadoop/Hive/DW RD 必須掌握的部分,之前也有幾篇文章聊到過 MR/Hive 中的 join,其實底層都是相同的,只是上層做了些封裝而已,如果你還不了解究竟 Join 有哪些方式,以及底層怎么實現的,請參考如下鏈接:
http://my.oschina.net/leejun2005/blog/95186?MapReduce 中的兩表 join 幾種方案簡介
http://my.oschina.net/leejun2005/blog/111963?Hadoop 多表 join:map side join 范例
http://my.oschina.net/leejun2005/blog/158491?Hive & Performance 學習筆記
在最后一篇鏈接中,有這么兩副圖:
前面兩個很好理解,基本上每個人都會接觸到,但最后一種,可能有同學還是比較陌生,SMB 存在的目的主要是為了解決大表與大表間的 Join 問題,分桶其實就是把大表化成了“小表”,然后 Map-Side Join 解決之,這是典型的分而治之的思想。在聊 SMB Join 之前,我們還是先復習下相關的基礎概念。
1、Hive 分區表
在Hive Select查詢中一般會掃描整個表內容,會消耗很多時間做沒必要的工作。有時候只需要掃描表中關心的一部分數據,因此建表時引入了partition概念。分區表指的是在創建表時指定的partition的分區空間。?
 Hive可以對數據按照某列或者某些列進行分區管理,所謂分區我們可以拿下面的例子進行解釋。?
 當前互聯網應用每天都要存儲大量的日志文件,幾G、幾十G甚至更大都是有可能。存儲日志,其中必然有個屬性是日志產生的日期。在產生分區時,就可以按照日志產生的日期列進行劃分。把每一天的日志當作一個分區。?
 將數據組織成分區,主要可以提高數據的查詢速度。至于用戶存儲的每一條記錄到底放到哪個分區,由用戶決定。即用戶在加載數據的時候必須顯示的指定該部分數據放到哪個分區。?
1.1 實現細節
1、一個表可以擁有一個或者多個分區,每個分區以文件夾的形式單獨存在表文件夾的目錄下。?
 2、表和列名不區分大小寫。?
 3、分區是以字段的形式在表結構中存在,通過describe table命令可以查看到字段存在,?但是該字段不存放實際的數據內容,僅僅是分區的表示(偽列)?。?
1.2 語法
1. 創建一個分區表,以 ds 為分區列:?
 create table invites (id int, name string) partitioned by (ds string) row format delimited fields terminated by 't' stored as textfile;?
 2. 將數據添加到時間為 2013-08-16 這個分區中:?
 load data local inpath '/home/hadoop/Desktop/data.txt' overwrite into table invites partition (ds='2013-08-16');?
 3. 將數據添加到時間為 2013-08-20 這個分區中:?
 load data local inpath '/home/hadoop/Desktop/data.txt' overwrite into table invites partition (ds='2013-08-20');?
 4. 從一個分區中查詢數據:?
 select * from invites where ds ='2013-08-12';?
 5. ?往一個分區表的某一個分區中添加數據:?
 insert overwrite table invites partition (ds='2013-08-12') select id,max(name) from test group by id;?
 可以查看分區的具體情況,使用命令:?
 hadoop fs -ls /home/hadoop.hive/warehouse/invites?
 或者:?
 show partitions tablename;
2、Hive 桶
對于每一個表(table)或者分區,?Hive可以進一步組織成桶,也就是說桶是更為細粒度的數據范圍劃分。Hive也是?針對某一列進行桶的組織。Hive采用對列值哈希,然后除以桶的個數求余的方式決定該條記錄存放在哪個桶當中。
把表(或者分區)組織成桶(Bucket)有兩個理由:
(1)獲得更高的查詢處理效率。桶為表加上了額外的結構,Hive 在處理有些查詢時能利用這個結構。具體而言,連接兩個在(包含連接列的)相同列上劃分了桶的表,可以使用 Map 端連接 (Map-side join)高效的實現。比如JOIN操作。對于JOIN操作兩個表有一個相同的列,如果對這兩個表都進行了桶操作。那么將保存相同列值的桶進行JOIN操作就可以,可以大大較少JOIN的數據量。
(2)使取樣(sampling)更高效。在處理大規模數據集時,在開發和修改查詢的階段,如果能在數據集的一小部分數據上試運行查詢,會帶來很多方便。
1. 創建帶桶的 table :
create table bucketed_user(id int,name string) clustered by (id) sorted by(name) into 4 buckets row format delimited fields terminated by '\t' stored as textfile;?
 首先,我們來看如何告訴Hive—個表應該被劃分成桶。我們使用CLUSTERED BY 子句來指定劃分桶所用的列和要劃分的桶的個數:?
 CREATE TABLE bucketed_user (id INT) name STRING)?
 CLUSTERED BY (id) INTO 4 BUCKETS;?
 在這里,我們使用用戶ID來確定如何劃分桶(Hive使用對值進行哈希并將結果除 以桶的個數取余數。這樣,任何一桶里都會有一個隨機的用戶集合(PS:其實也能說是隨機,不是嗎?)。?
 對于map端連接的情況,兩個表以相同方式劃分桶。處理左邊表內某個桶的 mapper知道右邊表內相匹配的行在對應的桶內。因此,mapper只需要獲取那個桶 (這只是右邊表內存儲數據的一小部分)即可進行連接。這一優化方法并不一定要求 兩個表必須桶的個數相同,兩個表的桶個數是倍數關系也可以。用HiveQL對兩個劃分了桶的表進行連接,可參見“map連接”部分(P400)。?
 桶中的數據可以根據一個或多個列另外進行排序。由于這樣對每個桶的連接變成了高效的歸并排序(merge-sort), 因此可以進一步提升map端連接的效率。以下語法聲明一個表使其使用排序桶:?
 CREATE TABLE bucketed_users (id INT, name STRING)?
 CLUSTERED BY (id) SORTED BY (id ASC) INTO 4 BUCKETS;?
 我們如何保證表中的數據都劃分成桶了呢?把在Hive外生成的數據加載到劃分成 桶的表中,當然是可以的。其實讓Hive來劃分桶更容易。這一操作通常針對已有的表。?
 Hive并不檢查數據文件中的桶是否和表定義中的桶一致(無論是對于桶 的數量或用于劃分桶的列)。如果兩者不匹配,在査詢時可能會碰到錯 誤或未定義的結果。因此,建議讓Hive來進行劃分桶的操作。?
 有一個沒有劃分桶的用戶表:?
 hive> SELECT * FROM users;?
 0 ? ?Nat?
 2 ? ?Doe?
 B ? ?Kay?
 4 ? ?Ann?
2. 強制多個 reduce 進行輸出:
要向分桶表中填充成員,需要將 hive.enforce.bucketing 屬性設置為 true。①這?樣,Hive 就知道用表定義中聲明的數量來創建桶。然后使用 INSERT 命令即可。需要注意的是:?clustered by和sorted by不會影響數據的導入,這意味著,用戶必須自己負責數據如何如何導入,包括數據的分桶和排序。?
 'set hive.enforce.bucketing = true' 可以自動控制上一輪reduce的數量從而適配bucket的個數,當然,用戶也可以自主設置mapred.reduce.tasks去適配bucket個數,推薦使用'set hive.enforce.bucketing = true'??
3. 往表中插入數據:
INSERT OVERWRITE TABLE bucketed_users SELECT * FROM users;?
 物理上,每個桶就是表(或分區)目錄里的一個文件。它的文件名并不重要,但是桶 n 是按照字典序排列的第 n 個文件。事實上,桶對應于 MapReduce 的輸出文件分區:一個作業產生的桶(輸出文件)和reduce任務個數相同。我們可以通過查看剛才 創建的bucketd_users表的布局來了解這一情況。運行如下命令:??
4. 查看表的結構:
hive> dfs -ls /user/hive/warehouse/bucketed_users;?
 將顯示有4個新建的文件。文件名如下(文件名包含時間戳,由Hive產生,因此 每次運行都會改變):?
 attempt_201005221636_0016_r_000000_0?
 attempt_201005221636_0016_r-000001_0?
 attempt_201005221636_0016_r_000002_0?
 attempt_201005221636_0016_r_000003_0?
 第一個桶里包括用戶IDO和4,因為一個INT的哈希值就是這個整數本身,在這里 除以桶數(4)以后的余數:②?
5. 讀取數據,看每一個文件的數據:
hive> dfs -cat /user/hive/warehouse/bucketed_users/*0_0;?
 0 Nat?
 4 Ann?
 用TABLESAMPLE子句對表進行取樣,我們可以獲得相同的結果。這個子句會將 查詢限定在表的一部分桶內,而不是使用整個表:
6. 對桶中的數據進行采樣:
hive> SELECT * FROM bucketed_users?
 > ? ?TABLESAMPLE(BUCKET 1 OUT OF 4 ON id);?
 0 Nat?
 4 Ann?
 桶的個數從1開始計數。因此,前面的查詢從4個桶的第一個中獲取所有的用戶。 對于一個大規模的、均勻分布的數據集,這會返回表中約四分之一的數據行。我們 也可以用其他比例對若干個桶進行取樣(因為取樣并不是一個精確的操作,因此這個 比例不一定要是桶數的整數倍)。例如,下面的查詢返回一半的桶:
7. 查詢一半返回的桶數:
hive> SELECT * FROM bucketed_users?
 > ? ?TABLESAMPLE(BUCKET 1 OUT OF 2 ON id);?
 0 Nat?
 4 Ann?
 2 Joe?
 因為查詢只需要讀取和TABLESAMPLE子句匹配的桶,所以取樣分桶表是非常高效?的操作。如果使用rand()函數對沒有劃分成桶的表進行取樣,即使只需要讀取很?小一部分樣本,也要掃描整個輸入數據集:?
 hive〉 SELECT * FROM users?
 > TABLESAMPLE(BUCKET 1 OUT OF 4 ON rand());?
 2 Doe?
 ①從Hive 0.6.0開始,對以前的版本,必須把mapred.reduce .tasks設為表中要填 充的桶的個數。如果桶是排序的,還需要把hive.enforce.sorting設為true。?
 ②顯式原始文件時,因為分隔字符是一個不能打印的控制字符,因此字段都擠在一起。?
3、舉個完整的小例子:
(1)建student & student1 表:
| 1 | create?table?student(id?INT, age?INT,?name?STRING) | 
| 2 | partitioned?by(stat_date STRING) | 
| 3 | clustered?by(id) sorted?by(age)?into?2 buckets | 
| 4 | row format delimited fields terminated?by?','; | 
| 5 | ? | 
| 6 | create?table?student1(id?INT, age?INT,?name?STRING) | 
| 7 | partitioned?by(stat_date STRING) | 
| 8 | clustered?by(id) sorted?by(age)?into?2 buckets | 
| 9 | row format delimited fields terminated?by?','; | 
(2)設置環境變量:
set hive.enforce.bucketing = true;??
(3)插入數據:
| 01 | cat bucket.txt | 
| 02 | ? | 
| 03 | 1,20,zxm | 
| 04 | 2,21,ljz | 
| 05 | 3,19,cds | 
| 06 | 4,18,mac | 
| 07 | 5,22,android | 
| 08 | 6,23,symbian | 
| 09 | 7,25,wp | 
| 10 | ? | 
| 11 | LOAD?DATA?local?INPATH?'/home/lijun/bucket.txt'?OVERWRITE?INTO?TABLE?student partition(stat_date="20120802"); | 
| 12 | ? | 
| 13 | from?student | 
| 14 | insert?overwrite?table?student1 partition(stat_date="20120802") | 
| 15 | select?id,age,name?where?stat_date="20120802"?sort?by?age; | 
(4)查看文件目錄:
hadoop fs -ls /hive/warehouse/test.db/student1/stat_date=20120802?
 Found 2 items?
 -rw-r--r-- ? 2 lijun supergroup ? ? ? ? 31 2013-11-24 19:16 /hive/warehouse/test.db/student1/stat_date=20120802/000000_0?
 -rw-r--r-- ? 2 lijun supergroup ? ? ? ? 39 2013-11-24 19:16 /hive/warehouse/test.db/student1/stat_date=20120802/000001_0?
(5)查看sampling數據:
hive> select * from student1 tablesample(bucket 1 out of 2 on id);
Total MapReduce jobs = 1
 Launching Job 1 out of 1
 .......
 OK
 4 ? ? ? 18 ? ? ?mac ? ? 20120802
 2 ? ? ? 21 ? ? ?ljz ? ? 20120802
 6 ? ? ? 23 ? ? ?symbian 20120802
 Time taken: 20.608 seconds
 注:tablesample是抽樣語句,語法:TABLESAMPLE(BUCKET x OUT OF y)
 y必須是table總bucket數的倍數或者因子。hive根據y的大小,決定抽樣的比例。例如,table總共分了64份,當y=32時,抽取(64/32=)2個bucket的數據,當y=128時,抽取(64/128=)1/2個bucket的數據。x表示從哪個bucket開始抽取。例如,table總bucket數為32,tablesample(bucket 3 out of 16),表示總共抽取(32/16=)2個bucket的數據,分別為第3個bucket和第(3+16=)19個bucket的數據。
4、Refer:
http://rdc.taobao.org/?p=1457??從MR到Hive – 一次遷移的過程
http://blog.573114.com/Blog/Html/A031/516857.html??Hadoop權威指南 第12章 Hive簡介 P384
http://superlxw1234.iteye.com/blog/1545150??hive--Sort Merge Bucket Map Join
http://blog.csdn.net/yfkiss/article/details/7816916??
轉載地址:轉:https://www.cnblogs.com/xiohao/p/6429305.html
總結
以上是生活随笔為你收集整理的Hive分区和桶的概念的全部內容,希望文章能夠幫你解決所遇到的問題。
 
                            
                        - 上一篇: 雅可比旋转求解对称二维矩阵的特征值和特征
- 下一篇: linux安装思源字体下载,CentOS
