共計 5726 個字符,預計需要花費 15 分鐘才能閱讀完成。
這篇文章給大家分享的是有關 Hive 中分區、桶的示例分析的內容。丸趣 TV 小編覺得挺實用的,因此分享給大家做個參考,一起跟隨丸趣 TV 小編過來看看吧。
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 表:
create table student(id INT, age INT, name STRING)
partitioned by(stat_date STRING)
clustered by(id) sorted by(age) into 2 buckets
row format delimited fields terminated by ,
create table student1(id INT, age INT, name STRING)
partitioned by(stat_date STRING)
clustered by(id) sorted by(age) into 2 buckets
row format delimited fields terminated by ,
(2)設置環境變量:
set hive.enforce.bucketing = true;
(3)插入數據:
cat bucket.txt
1,20,zxm
2,21,ljz
3,19,cds
4,18,mac
5,22,android
6,23,symbian
7,25,wp
LOAD DATA local INPATH /home/lijun/bucket.txt OVERWRITE INTO TABLE student partition(stat_date= 20120802
from student
insert overwrite table student1 partition(stat_date= 20120802)
select id,age,name where stat_date= 20120802
(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 的數據。
感謝各位的閱讀!關于“Hive 中分區、桶的示例分析”這篇文章就分享到這里了,希望以上內容可以對大家有一定的幫助,讓大家可以學到更多知識,如果覺得文章不錯,可以把它分享出去讓更多的人看到吧!