大數據工程師必會的知識點之一:關於hive的分區和分桶

大數據工程師必會的知識點之一:關於hive的分區和分桶

 

1、Hive分區表

在Hive Select查詢中一般會掃描整個表內容,會消耗很多時間做沒必要的工作。有時候只需要掃描表中關心的一部分數據,因此建表時引入了partition概念。分區表指的是在創建表時指定的partition的分區空間。 Hive可以對數據按照某列或者某些列進行分區管理,所謂分區我們可以拿下面的例子進行解釋。

當前互聯網應用每天都要存儲大量的日誌文件,幾G、幾十G甚至更大都是有可能。存儲日誌,其中必然有個屬性是日誌產生的日期。在產生分區時,就可以按照日誌產生的日期列進行劃分。把每一天的日誌當作一個分區。

將數據組織成分區,主要可以提高數據的查詢速度。至於用戶存儲的每一條記錄到底放到哪個分區,由用戶決定。即用戶在加載數據的時候必須顯示的指定該部分數據放到哪個分區。

1.1實現細節

1、一個表可以擁有一個或者多個分區,每個分區以文件夾的形式單獨存在表文件夾的目錄下。

2、表和列名不區分大小寫。

3、分區是以字段的形式在表結構中存在,通過describetable命令可以查看到字段存在, 但是該字段不存放實際的數據內容,僅僅是分區的表示(僞列) 。

1.2語法

1.創建一個分區表,以 ds 爲分區列:

create table invites(id int, name string) partitioned by (ds string) row format delimited fieldsterminated by '' 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 inviteswhere ds ='2013-08-12';

5. 往一個分區表的某一個分區中添加數據:

insert overwrite tableinvites partition (ds='2013-08-12') select id,max(name) from test group by id;

可以查看分區的具體情況,使用命令:

hadoop fs -ls /home/hadoop.hive/warehouse/invites

或者:

show partitionstablename;

大數據工程師必會的知識點之一:關於hive的分區和分桶

 

2、Hive桶

對於每一個表(table)或者分區, Hive可以進一步組織成桶,也就是說桶是更爲細粒度的數據範圍劃分。Hive也是 針對某一列進行桶的組織。Hive採用對列值哈希,然後除以桶的個數求餘的方式決定該條記錄存放在哪個桶當中。

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

(1)獲得更高的查詢處理效率。桶爲表加上了額外的結構,Hive 在處理有些查詢時能利用這個結構。具體而言,連接兩個在(包含連接列的)相同列上劃分了桶的表,可以使用 Map 端連接 (Map-side join)高效的實現。比如JOIN操作。對於JOIN操作兩個表有一個相同的列,如果對這兩個表都進行了桶操作。那麼將保存相同列值的桶進行JOIN操作就可以,可以大大較少JOIN的數據量。

(2)使取樣(sampling)更高效。在處理大規模數據集時,在開發和修改查詢的階段,如果能在數據集的一小部分數據上試運行查詢,會帶來很多方便。

1.創建帶桶的 table :

create tablebucketed_user(id int,name string)clustered by (id) sorted by(name) into 4buckets row format delimited fields terminated by '' stored as textfile;

首先,我們來看如何告訴Hive

—個表應該被劃分成桶。我們使用CLUSTERED BY 子句來指定劃分桶所用的列和要劃分的桶的個數:

CREATE TABLE bucketed_user(id INT) name STRING)

CLUSTERED BY (id) INTO 4BUCKETS; 在這裏,我們使用用戶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來進行劃分桶的操作。

2. 往表中插入數據:

INSERT OVERWRITE TABLEbucketed_users SELECT * FROM users; 物理上,每個桶就是表(

或分區)目錄裏的一個文件。它的文件名並不重要,但是桶 n 是按照字典序排列的第 n 個文件。

事實上,桶對應於 MapReduce

的輸出文件分區:一個作業產生的桶(輸出文件)和reduce任務個數相同.

3. 對桶中的數據進行採樣:

hive> SELECT * FROMbucketed_users

> TABLESAMPLE(BUCKET 1 OUT OF 4 ON id);

0 Nat

4 Ann 桶的個數從1

開始計數。因此,前面的查詢從4個桶的第一個中獲取所有的用戶。 對於一個大規模的、均勻分佈的數據集,這會返回表中約四分之一的數據行。我們 也可以用其他比例對若干個桶進行取樣(因爲取樣並不是一個精確的操作,因此這個 比例不一定要是桶數的整數倍)。

注:tablesample是抽樣語句,語法:TABLESAMPLE(BUCKET x OUTOF 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的數據。

總結

分區按照我們指定列範圍進行分區(層級文件夾),而分桶是按照列值的hash值,這樣想同值都會在一個桶內(一級文件夾內不同文件區別不同的桶),便於join操作。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章