Hive分區(qū)和桶的概念

Hive 已是目前業(yè)界最為通用滑蚯、廉價(jià)的構(gòu)建大數(shù)據(jù)時(shí)代數(shù)據(jù)倉(cāng)庫(kù)的解決方案了浪蹂,雖然也有 Impala 等后起之秀,但目前從功能告材、穩(wěn)定性等方面來(lái)說(shuō)坤次,Hive 的地位尚不可撼動(dòng)。

其實(shí)這篇博文主要是想聊聊 SMB join 的斥赋,Join 是整個(gè) MR/Hive 最為核心的部分之一浙踢,是每個(gè)Hadoop/Hive/DW RD 必須掌握的部分,之前也有幾篇文章聊到過(guò) MR/Hive 中的 join灿渴,其實(shí)底層都是相同的洛波,只是上層做了些封裝而已胰舆,如果你還不了解究竟 Join 有哪些方式,以及底層怎么實(shí)現(xiàn)的蹬挤,請(qǐng)參考如下鏈接:

http://my.oschina.net/leejun2005/blog/95186 MapReduce 中的兩表 join 幾種方案簡(jiǎn)介

http://my.oschina.net/leejun2005/blog/111963 Hadoop 多表 join:map side join 范例

http://my.oschina.net/leejun2005/blog/158491 Hive & Performance 學(xué)習(xí)筆記

在最后一篇鏈接中缚窿,有這么兩副圖:

image.png

前面兩個(gè)很好理解,基本上每個(gè)人都會(huì)接觸到焰扳,但最后一種倦零,可能有同學(xué)還是比較陌生,SMB 存在的目的主要是為了解決大表與大表間的 Join 問(wèn)題吨悍,分桶其實(shí)就是把大表化成了“小表”扫茅,然后 Map-Side Join 解決之,這是典型的分而治之的思想育瓜。在聊 SMB Join 之前葫隙,我們還是先復(fù)習(xí)下相關(guān)的基礎(chǔ)概念。

1躏仇、Hive 分區(qū)表

在Hive Select查詢(xún)中一般會(huì)掃描整個(gè)表內(nèi)容恋脚,會(huì)消耗很多時(shí)間做沒(méi)必要的工作。有時(shí)候只需要掃描表中關(guān)心的一部分?jǐn)?shù)據(jù)焰手,因此建表時(shí)引入了partition概念糟描。分區(qū)表指的是在創(chuàng)建表時(shí)指定的partition的分區(qū)空間。

Hive可以對(duì)數(shù)據(jù)按照某列或者某些列進(jìn)行分區(qū)管理书妻,所謂分區(qū)我們可以拿下面的例子進(jìn)行解釋船响。
當(dāng)前互聯(lián)網(wǎng)應(yīng)用每天都要存儲(chǔ)大量的日志文件,幾G躲履、幾十G甚至更大都是有可能灿意。存儲(chǔ)日志,其中必然有個(gè)屬性是日志產(chǎn)生的日期崇呵。在產(chǎn)生分區(qū)時(shí),就可以按照日志產(chǎn)生的日期列進(jìn)行劃分馅袁。把每一天的日志當(dāng)作一個(gè)分區(qū)域慷。
將數(shù)據(jù)組織成分區(qū),主要可以提高數(shù)據(jù)的查詢(xún)速度汗销。至于用戶存儲(chǔ)的每一條記錄到底放到哪個(gè)分區(qū)犹褒,由用戶決定。即用戶在加載數(shù)據(jù)的時(shí)候必須顯示的指定該部分?jǐn)?shù)據(jù)放到哪個(gè)分區(qū)弛针。

1.1 實(shí)現(xiàn)細(xì)節(jié)

1叠骑、一個(gè)表可以擁有一個(gè)或者多個(gè)分區(qū),每個(gè)分區(qū)以文件夾的形式單獨(dú)存在表文件夾的目錄下削茁。
2宙枷、表和列名不區(qū)分大小寫(xiě)掉房。
3、分區(qū)是以字段的形式在表結(jié)構(gòu)中存在慰丛,通過(guò)describe table命令可以查看到字段存在卓囚, 但是該字段不存放實(shí)際的數(shù)據(jù)內(nèi)容,僅僅是分區(qū)的表示(偽列) 诅病。

1.2 語(yǔ)法

1. 創(chuàng)建一個(gè)分區(qū)表哪亿,以 ds 為分區(qū)列:
create table invites (id int, name string) partitioned by (ds string) row format delimited fields terminated by 't' stored as textfile;
2. 將數(shù)據(jù)添加到時(shí)間為 2013-08-16 這個(gè)分區(qū)中:
load data local inpath '/home/hadoop/Desktop/data.txt' overwrite into table invites partition (ds='2013-08-16');
3. 將數(shù)據(jù)添加到時(shí)間為 2013-08-20 這個(gè)分區(qū)中:
load data local inpath '/home/hadoop/Desktop/data.txt' overwrite into table invites partition (ds='2013-08-20');
4. 從一個(gè)分區(qū)中查詢(xún)數(shù)據(jù):
select * from invites where ds ='2013-08-12';
5. 往一個(gè)分區(qū)表的某一個(gè)分區(qū)中添加數(shù)據(jù):
insert overwrite table invites partition (ds='2013-08-12') select id,max(name) from test group by id;
可以查看分區(qū)的具體情況,使用命令:
hadoop fs -ls /home/hadoop.hive/warehouse/invites
或者:
show partitions tablename;

2贤笆、Hive 桶

對(duì)于每一個(gè)表(table)或者分區(qū)蝇棉, Hive可以進(jìn)一步組織成桶,也就是說(shuō)桶是更為細(xì)粒度的數(shù)據(jù)范圍劃分芥永。Hive也是 針對(duì)某一列進(jìn)行桶的組織篡殷。Hive采用對(duì)列值哈希,然后除以桶的個(gè)數(shù)求余的方式?jīng)Q定該條記錄存放在哪個(gè)桶當(dāng)中恤左。

把表(或者分區(qū))組織成桶(Bucket)有兩個(gè)理由:

(1)獲得更高的查詢(xún)處理效率贴唇。桶為表加上了額外的結(jié)構(gòu),Hive 在處理有些查詢(xún)時(shí)能利用這個(gè)結(jié)構(gòu)飞袋。具體而言戳气,連接兩個(gè)在(包含連接列的)相同列上劃分了桶的表,可以使用 Map 端連接 (Map-side join)高效的實(shí)現(xiàn)巧鸭。比如JOIN操作瓶您。對(duì)于JOIN操作兩個(gè)表有一個(gè)相同的列,如果對(duì)這兩個(gè)表都進(jìn)行了桶操作纲仍。那么將保存相同列值的桶進(jìn)行JOIN操作就可以呀袱,可以大大較少JOIN的數(shù)據(jù)量。

(2)使取樣(sampling)更高效郑叠。在處理大規(guī)模數(shù)據(jù)集時(shí)夜赵,在開(kāi)發(fā)和修改查詢(xún)的階段,如果能在數(shù)據(jù)集的一小部分?jǐn)?shù)據(jù)上試運(yùn)行查詢(xún)乡革,會(huì)帶來(lái)很多方便寇僧。

1. 創(chuàng)建帶桶的 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;
首先,我們來(lái)看如何告訴Hive—個(gè)表應(yīng)該被劃分成桶沸版。我們使用CLUSTERED BY 子句來(lái)指定劃分桶所用的列和要?jiǎng)澐值耐暗膫€(gè)數(shù):

CREATE TABLE bucketed_user (id INT) name STRING)
CLUSTERED BY (id) INTO 4 BUCKETS;

在這里嘁傀,我們使用用戶ID來(lái)確定如何劃分桶(Hive使用對(duì)值進(jìn)行哈希并將結(jié)果除 以桶的個(gè)數(shù)取余數(shù)。這樣视粮,任何一桶里都會(huì)有一個(gè)隨機(jī)的用戶集合(PS:其實(shí)也能說(shuō)是隨機(jī)细办,不是嗎?)蕾殴。

對(duì)于map端連接的情況笑撞,兩個(gè)表以相同方式劃分桶岛啸。處理左邊表內(nèi)某個(gè)桶的 mapper知道右邊表內(nèi)相匹配的行在對(duì)應(yīng)的桶內(nèi)。因此娃殖,mapper只需要獲取那個(gè)桶 (這只是右邊表內(nèi)存儲(chǔ)數(shù)據(jù)的一小部分)即可進(jìn)行連接琉苇。這一優(yōu)化方法并不一定要求 兩個(gè)表必須桶的個(gè)數(shù)相同已烤,兩個(gè)表的桶個(gè)數(shù)是倍數(shù)關(guān)系也可以。用HiveQL對(duì)兩個(gè)劃分了桶的表進(jìn)行連接,可參見(jiàn)“map連接”部分(P400)诱渤。

桶中的數(shù)據(jù)可以根據(jù)一個(gè)或多個(gè)列另外進(jìn)行排序仍秤。由于這樣對(duì)每個(gè)桶的連接變成了高效的歸并排序(merge-sort), 因此可以進(jìn)一步提升map端連接的效率畴博。以下語(yǔ)法聲明一個(gè)表使其使用排序桶:

CREATE TABLE bucketed_users (id INT, name STRING)
CLUSTERED BY (id) SORTED BY (id ASC) INTO 4 BUCKETS;

我們?nèi)绾伪WC表中的數(shù)據(jù)都劃分成桶了呢吮成?把在Hive外生成的數(shù)據(jù)加載到劃分成 桶的表中,當(dāng)然是可以的郁稍。其實(shí)讓Hive來(lái)劃分桶更容易赦政。這一操作通常針對(duì)已有的表。

Hive并不檢查數(shù)據(jù)文件中的桶是否和表定義中的桶一致(無(wú)論是對(duì)于桶 的數(shù)量或用于劃分桶的列)耀怜。如果兩者不匹配恢着,在査詢(xún)時(shí)可能會(huì)碰到錯(cuò) 誤或未定義的結(jié)果。因此财破,建議讓Hive來(lái)進(jìn)行劃分桶的操作掰派。

有一個(gè)沒(méi)有劃分桶的用戶表:
hive> SELECT * FROM users;
0 Nat
2 Doe
B Kay
4 Ann

2. 強(qiáng)制多個(gè) reduce 進(jìn)行輸出:

要向分桶表中填充成員,需要將 hive.enforce.bucketing 屬性設(shè)置為 true左痢。①這 樣靡羡,Hive 就知道用表定義中聲明的數(shù)量來(lái)創(chuàng)建桶。然后使用 INSERT 命令即可俊性。需要注意的是: clustered by和sorted by不會(huì)影響數(shù)據(jù)的導(dǎo)入略步,這意味著,用戶必須自己負(fù)責(zé)數(shù)據(jù)如何如何導(dǎo)入定页,包括數(shù)據(jù)的分桶和排序趟薄。
'set hive.enforce.bucketing = true' 可以自動(dòng)控制上一輪reduce的數(shù)量從而適配bucket的個(gè)數(shù),當(dāng)然典徊,用戶也可以自主設(shè)置mapred.reduce.tasks去適配bucket個(gè)數(shù)杭煎,推薦使用'set hive.enforce.bucketing = true'

3. 往表中插入數(shù)據(jù):

INSERT OVERWRITE TABLE bucketed_users SELECT * FROM users;

物理上,每個(gè)桶就是表(或分區(qū))目錄里的一個(gè)文件宫峦。它的文件名并不重要,但是桶 n 是按照字典序排列的第 n 個(gè)文件玫鸟。事實(shí)上导绷,桶對(duì)應(yīng)于 MapReduce 的輸出文件分區(qū):一個(gè)作業(yè)產(chǎn)生的桶(輸出文件)和reduce任務(wù)個(gè)數(shù)相同。我們可以通過(guò)查看剛才 創(chuàng)建的bucketd_users表的布局來(lái)了解這一情況屎飘。運(yùn)行如下命令:

4. 查看表的結(jié)構(gòu):

hive> dfs -ls /user/hive/warehouse/bucketed_users;
將顯示有4個(gè)新建的文件妥曲。文件名如下(文件名包含時(shí)間戳,由Hive產(chǎn)生褂萧,因此 每次運(yùn)行都會(huì)改變):
attempt_201005221636_0016_r_000000_0
attempt_201005221636_0016_r-000001_0
attempt_201005221636_0016_r_000002_0
attempt_201005221636_0016_r_000003_0
第一個(gè)桶里包括用戶IDO和4导犹,因?yàn)橐粋€(gè)INT的哈希值就是這個(gè)整數(shù)本身谎痢,在這里 除以桶數(shù)(4)以后的余數(shù):②

5. 讀取數(shù)據(jù)节猿,看每一個(gè)文件的數(shù)據(jù):

hive> dfs -cat /user/hive/warehouse/bucketed_users/*0_0;
0 Nat
4 Ann

用TABLESAMPLE子句對(duì)表進(jìn)行取樣滨嘱,我們可以獲得相同的結(jié)果太雨。這個(gè)子句會(huì)將 查詢(xún)限定在表的一部分桶內(nèi),而不是使用整個(gè)表:

6. 對(duì)桶中的數(shù)據(jù)進(jìn)行采樣:

hive> SELECT * FROM bucketed_users

TABLESAMPLE(BUCKET 1 OUT OF 4 ON id);
0 Nat
4 Ann

桶的個(gè)數(shù)從1開(kāi)始計(jì)數(shù)宪拥。因此铣减,前面的查詢(xún)從4個(gè)桶的第一個(gè)中獲取所有的用戶。 對(duì)于一個(gè)大規(guī)模的缔刹、均勻分布的數(shù)據(jù)集校镐,這會(huì)返回表中約四分之一的數(shù)據(jù)行捺典。我們 也可以用其他比例對(duì)若干個(gè)桶進(jìn)行取樣(因?yàn)槿硬⒉皇且粋€(gè)精確的操作,因此這個(gè) 比例不一定要是桶數(shù)的整數(shù)倍)牍陌。例如毒涧,下面的查詢(xún)返回一半的桶:

7. 查詢(xún)一半返回的桶數(shù):

hive> SELECT * FROM bucketed_users

TABLESAMPLE(BUCKET 1 OUT OF 2 ON id)契讲;
0 Nat
4 Ann
2 Joe

因?yàn)椴樵?xún)只需要讀取和TABLESAMPLE子句匹配的桶,所以取樣分桶表是非常高效 的操作霹琼。如果使用rand()函數(shù)對(duì)沒(méi)有劃分成桶的表進(jìn)行取樣凉当,即使只需要讀取很 小一部分樣本看杭,也要掃描整個(gè)輸入數(shù)據(jù)集:

hive〉 SELECT * FROM users

TABLESAMPLE(BUCKET 1 OUT OF 4 ON rand());
2 Doe

①?gòu)腍ive 0.6.0開(kāi)始楼雹,對(duì)以前的版本贮缅,必須把mapred.reduce .tasks設(shè)為表中要填 充的桶的個(gè)數(shù)谴供。如果桶是排序的,還需要把hive.enforce.sorting設(shè)為true桂肌。
②顯式原始文件時(shí)数焊,因?yàn)榉指糇址且粋€(gè)不能打印的控制字符崎场,因此字段都擠在一起佩耳。

3谭跨、舉個(gè)完整的小例子:

(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)設(shè)置環(huán)境變量:

set hive.enforce.bucketing = true;

(3)插入數(shù)據(jù):

| 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數(shù)據(jù):

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是抽樣語(yǔ)句干厚,語(yǔ)法:TABLESAMPLE(BUCKET x OUT OF y)
y必須是table總bucket數(shù)的倍數(shù)或者因子。hive根據(jù)y的大小污呼,決定抽樣的比例。例如,table總共分了64份苗缩,當(dāng)y=32時(shí),抽取(64/32=)2個(gè)bucket的數(shù)據(jù),當(dāng)y=128時(shí)泻肯,抽取(64/128=)1/2個(gè)bucket的數(shù)據(jù)渊迁。x表示從哪個(gè)bucket開(kāi)始抽取。例如灶挟,table總bucket數(shù)為32琉朽,tablesample(bucket 3 out of 16),表示總共抽戎上场(32/16=)2個(gè)bucket的數(shù)據(jù)箱叁,分別為第3個(gè)bucket和第(3+16=)19個(gè)bucket的數(shù)據(jù)。

4惕医、Refer:

http://rdc.taobao.org/?p=1457 從MR到Hive – 一次遷移的過(guò)程

http://blog.573114.com/Blog/Html/A031/516857.html Hadoop權(quán)威指南 第12章 Hive簡(jiǎn)介 P384

http://superlxw1234.iteye.com/blog/1545150 hive--Sort Merge Bucket Map Join

http://blog.csdn.net/yfkiss/article/details/7816916

參考鏈接:http://blog.csdn.net/wisgood/article/details/17186107

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末耕漱,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子曹锨,更是在濱河造成了極大的恐慌孤个,老刑警劉巖,帶你破解...
    沈念sama閱讀 222,104評(píng)論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件沛简,死亡現(xiàn)場(chǎng)離奇詭異齐鲤,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)椒楣,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,816評(píng)論 3 399
  • 文/潘曉璐 我一進(jìn)店門(mén)给郊,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人捧灰,你說(shuō)我怎么就攤上這事淆九⊥炒福” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 168,697評(píng)論 0 360
  • 文/不壞的土叔 我叫張陵炭庙,是天一觀的道長(zhǎng)饲窿。 經(jīng)常有香客問(wèn)我,道長(zhǎng)焕蹄,這世上最難降的妖魔是什么逾雄? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 59,836評(píng)論 1 298
  • 正文 為了忘掉前任,我火速辦了婚禮腻脏,結(jié)果婚禮上鸦泳,老公的妹妹穿的比我還像新娘。我一直安慰自己永品,他們只是感情好做鹰,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,851評(píng)論 6 397
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著鼎姐,像睡著了一般钾麸。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上炕桨,一...
    開(kāi)封第一講書(shū)人閱讀 52,441評(píng)論 1 310
  • 那天喂走,我揣著相機(jī)與錄音,去河邊找鬼谋作。 笑死芋肠,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的遵蚜。 我是一名探鬼主播帖池,決...
    沈念sama閱讀 40,992評(píng)論 3 421
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼吭净!你這毒婦竟也來(lái)了睡汹?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 39,899評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤寂殉,失蹤者是張志新(化名)和其女友劉穎囚巴,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體友扰,經(jīng)...
    沈念sama閱讀 46,457評(píng)論 1 318
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡彤叉,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,529評(píng)論 3 341
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了村怪。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片秽浇。...
    茶點(diǎn)故事閱讀 40,664評(píng)論 1 352
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖甚负,靈堂內(nèi)的尸體忽然破棺而出柬焕,到底是詐尸還是另有隱情审残,我是刑警寧澤,帶...
    沈念sama閱讀 36,346評(píng)論 5 350
  • 正文 年R本政府宣布斑举,位于F島的核電站搅轿,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏富玷。R本人自食惡果不足惜介时,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 42,025評(píng)論 3 334
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望凌彬。 院中可真熱鬧,春花似錦循衰、人聲如沸铲敛。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 32,511評(píng)論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)伐蒋。三九已至,卻和暖如春迁酸,著一層夾襖步出監(jiān)牢的瞬間先鱼,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,611評(píng)論 1 272
  • 我被黑心中介騙來(lái)泰國(guó)打工奸鬓, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留焙畔,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 49,081評(píng)論 3 377
  • 正文 我出身青樓串远,卻偏偏與公主長(zhǎng)得像宏多,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子澡罚,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,675評(píng)論 2 359

推薦閱讀更多精彩內(nèi)容