Hive分桶之BUCKET詳解

韓師學子--胖佳發表於2019-03-24

                 Hive分桶之BUCKET詳解


轉載:https://blog.csdn.net/m0_37534613/article/details/55258928

 Bucket

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

把表(或者分割槽)組織成桶(Bucket)有兩個理由: 
(1)獲得更高的查詢處理效率。桶為表加上了額外的結構,Hive 在處理有些查詢時能利用這個結構。具體而言,連線兩個在(包含連線列的)相同列上劃分了桶的表,可以使用 Map 端連線 (Map-side join)高效的實現。比如JOIN操作。對於JOIN操作兩個表有一個相同的列,如果對這兩個表都進行了桶操作。那麼將儲存相同列值的桶進行JOIN操作就可以,可以大大較少JOIN的資料量。 
(2)使取樣(sampling)更高效。在處理大規模資料集時,在開發和修改查詢的階段,如果能在資料集的一小部分資料上試執行查詢,會帶來很多方便。

下面來一個例子:

Create table dz_test(
    id  bigint  comment’編號’,(ps:comment為註釋)
    name string comment’姓名’
)comment’編號與姓名錶’
Partitioned by(pdate string)
Clustered by(id)     按id分桶,自動雜湊分桶
Sorted by(id)   按id排序
Into 4 buckets   分成4個桶
Row format delimited 設定建立的表在載入資料的時候,支援的列分隔符
Fields terminated by ‘\t’  每個欄位按\t分割
Lines terminated by’\n’ stored as textfile; 按\n為斷行符,指定匯入的檔案為純文字。
Hive本身支援的檔案格式只有:Text File,Sequence File,如果資料需要壓縮,使用 [STORED AS SEQUENCE]

夠詳細了吧,下面load資料
插入資料之前需要設定引數hive.enforce.bucketing=true,以強制hive的reducer數目為分桶數。如果不設定這個hive引數,最後的桶個數可能不是建表語句中的個數。另外,也可以通過將引數mapred.reduce.tasks設定為桶的數目來控制reducer的數目,建議採用第一種方式。

Set hive.enforce.bucketing=true;
Load data local inpath’/home/Hadoop/….’ overwrite into table dz_test partition(pdate=‘2015-10’)

物理上,每個桶就是表(或分割槽)目錄裡的一個檔案。它的檔名並不重要,但是桶 n 是按照字典序排列的第 n 個檔案。事實上,桶對應於 MapReduce 的輸出檔案分割槽:一個作業產生的桶(輸出檔案)和reduce任務個數相同。

我們可以通過檢視剛才 建立的bucketd_users表的佈局來了解這一情況。

檢視錶的結構:

hive> dfs -ls /user/hive/warehouse/dz_test; 


將顯示有4個新建的檔案。檔名如下(檔名包含時間戳,由Hive產生,因此 每次執行都會改變): 
attempt_201701221636_0016_r_000000_0 
attempt_201701221636_0016_r-000001_0 
attempt_201701221636_0016_r_000002_0 
attempt_201701221636_0016_r_000003_0 
第一個桶裡包括使用者ID和4,因為一個INT的雜湊值就是這個整數本身,在這裡 除以桶數(4)以後的餘數:2
讀取資料,看每一個檔案的資料:

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


用TABLESAMPLE子句對錶進行取樣,我們可以獲得相同的結果。這個子句會將 查詢限定在表的一部分桶內,而不是使用整個表:
. 對桶中的資料進行取樣:

hive> SELECT * FROM dz_test 
>TABLESAMPLE(BUCKET 1 OUT OF 4 ON id); 
0 Nat 
4 Ann 


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

hive> SELECT * FROM dz_test 
>    TABLESAMPLE(BUCKET 1 OUT OF 2 ON id); 
0 Nat 
4 Ann 
2 Joe 


因為查詢只需要讀取和TABLESAMPLE子句匹配的桶,所以取樣分桶表是非常高效 的操作。如果使用rand()函式對沒有劃分成桶的表進行取樣,即使只需要讀取很 小一部分樣本,也要掃描整個輸入資料集: 

hive〉 SELECT * FROM dz_test 
> TABLESAMPLE(BUCKET 1 OUT OF 4 ON rand()); 
2 Doe 


①從Hive 0.6.0開始,對以前的版本,必須把mapred.reduce .tasks設為表中要填 充的桶的個數。如果桶是排序的,還需要把hive.enforce.sorting設為true。 
②顯式原始檔案時,因為分隔字元是一個不能列印的控制字元,因此欄位都擠在一起。 
 

相關文章