1. 程式人生 > >Hive 分割槽 分桶使用

Hive 分割槽 分桶使用

 為了對錶進行合理的管理以及提高查詢效率,Hive可以將表組織成“分割槽”。

  分割槽是表的部分列的集合,可以為頻繁使用的資料建立分割槽,這樣查詢分割槽中的資料時就不需要掃描全表,這對於提高查詢效率很有幫助。

    分割槽是一種根據“分割槽列”(partition column)的值對錶進行粗略劃分的機制。Hive中的每個分割槽對應資料庫中相應分割槽列的一個索引,每個分割槽對應著表下的一個目錄,在HDFS上的表現形式與表在HDFS上的表現形式相同,都是以子目錄的形式存在。

  一個表可以在多個維度上進行分割槽,並且分割槽可以巢狀使用。建分割槽需要在建立表時通過PARTITIONED BY子句指定,例如:

CREATE TABLE logs(
timestamp BIGINT,
line STRING
)
PARTITIONED BY (date STRING,country STRING);

  在將資料載入到表內之前,需要資料載入人員明確知道所載入的資料屬於哪一個分割槽。

  使用分割槽在某些應用場景下能給有效地提高效能,當只需要遍歷某一個小範圍內的資料或者一定條件下的資料時,它可以有效減少掃描資料的數量,前提是需要將資料匯入到分割槽內。

  注意:PARTITONED BY子句中定義的列是表中正式的列(分割槽列),但是資料檔案內並不包含這些列

 在Hive裡,為什麼要分割槽?

       龐大的資料集可能需要耗費大量的時間去處理。在許多場景下,可以通過分割槽或切片的方法減少每一次掃描總資料量,這種做法可以顯著地改善效能。

資料會依照單個或多個列進行分割槽,通常按照時間、地域或者是商業維度進行分割槽。比如vido表,分割槽的依據可以是電影的種類和評級,另外,按照拍攝時間劃分可能會得到更一致的結果。為了達到效能表現的一致性,對不同列的劃分應該讓資料儘可能均勻分佈。最好的情況下,分割槽的劃分條件總是能夠對應where語句的部分查詢條件。

  Hive的分割槽使用HDFS的子目錄功能實現。每一個子目錄包含了分割槽對應的列名和每一列的值。但是由於HDFS並不支援大量的子目錄,這也給分割槽的使用帶來了限制。我們有必要對錶中的分割槽數量進行預估,從而避免因為分割槽數量過大帶來一系列問題。

  Hive查詢通常使用分割槽的列作為查詢條件。這樣的做法可以指定MapReduce任務在HDFS中指定的子目錄下完成掃描的工作。HDFS的檔案目錄結構可以像索引一樣高效利用。


Hive還可以把表或分割槽,組織成桶。將表或分割槽組織成桶有以下幾個目的:

  第一個目的是為看取樣更高效,因為在處理大規模的資料集時,在開發、測試階段將所有的資料全部處理一遍可能不太現實,這時取樣就必不可少。

  第二個目的是為了獲得更好的查詢處理效率。

        桶為了表提供了額外的結構,Hive在處理某些查詢時利用這個結構,能給有效地提高查詢效率。

        桶是通過對指定列進行雜湊計算來實現的,通過雜湊值將一個列名下的資料切分為一組桶,並使每個桶對應於該列名下的一個儲存檔案

    在建立桶之前,需要設定hive.enforce.bucketing屬性為true,使得hive能識別桶。

  以下為建立帶有桶的表的語句:

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

   向桶中插入資料,這裡按照使用者id分成了4個桶,在插入資料時對應4個reduce操作,輸出4個檔案。

分割槽中的資料可以被進一步拆分成桶,bucket,不同於分割槽對列直接進行拆分,桶往往使用列的雜湊值進行資料取樣。

在分割槽數量過於龐大以至於可能導致檔案系統崩潰時,建議使用桶。

  桶的數量是固定的。

  Hive使用基於列的雜湊函式對資料打散,並分發到各個不同的桶中從而完成資料的分桶過程。

  注意,hive使用對分桶所用的值進行hash,並用hash結果除以桶的個數做取餘運算的方式來分桶保證了每個桶中都有資料,但每個桶中的資料條數不一定相等

  雜湊函式的選擇依賴於桶操作所針對的列的資料型別。除了資料取樣,桶操作也可以用來實現高效的Map端連線操作。

   記住,分桶比分割槽,更高的查詢效率

如何進行桶操作?

  例子1

1、建立臨時表 student_tmp,並匯入資料。

hive> desc student_tmp;
hive> select * from student_tmp;

 2、建立 student 表。經過分割槽操作過後的表已經被拆分成2個桶。

複製程式碼
create table student(
id int,
age int,
name string
)
partitioned by (stat_date string)
clustered by (id) sorted by(age) into 2 bucket
row format delimited fields terminated by ',';
複製程式碼

  分割槽中的資料可以被進一步拆分成桶!!!正確理解

  所有,桶,先partitioned by (stat_date string),再,clustered by (id) sorted by(age) into 2 bucket 

 3、設定環境變數。

hive> set hive.enforce.bucketing=true;

 4、插入資料

hive> from student_tmp
insert overwrite table student partition(stat_date='2015-01-19')
select id,age,name where stat_date='2015-01-18' sort by age;

 這都是固定的格式,一環扣一環的。


5、檢視檔案目錄
$ hadoop fs -ls /usr/hive/warehouse/student/stat_date=2015-01-19/


6、檢視 sampling 資料。
tablesample 是抽樣語句,語法如下
tablesample(bucket x out of y)
y 必須是 table 中 BUCKET 總數的倍數或者因子。 

例子2

  在下面的例子中,經過分割槽操作過後的表已經被拆分成100個桶。

複製程式碼
CREATE EXTERNAL TABLE videos_b(
prodicer string,
title string,
category string
)
PARTITIONED BY(year int)
CLUSTERED BY(title)INTO 100 BUCKETS;
複製程式碼

  現在,我們開始填充這張帶桶操作的表:

set hive.enfirce.bucketinig=true;
FROM videos
INSERT OVERWRITE TABLE videos_b
PARTITION(year=1999)
SELECT producer,title,string WHERE year=2009;

  如果不使用set hive.enforce.bucketing=true這項屬性,我們需要顯式地宣告set mapred.reduce.tasks=100來設定Reducer的數量。

此外,還需要在SELECT語句後面加上CLUSTERBY來實現INSERT查詢。

  下面是不使用桶設定的例子:

set mapred.reduce.tasks=100;
FROM videos
INSERT OVERWRITE TABLE videos_b
PARTITION(year=1999)
SELECT producer,title,string WHERE year=2009 CLUSTER BY title;

在Hive的文件中可以找到有關桶的更多細節:

https://cwiki.apache.org/confluence/display/Hive/LanguageManual+DDL

網上有篇關於hive的partition的使用講解的比較好,轉載了:

一、背景

1、在Hive Select查詢中一般會掃描整個表內容,會消耗很多時間做沒必要的工作。有時候只需要掃描表中關心的一部分資料,因此建表時引入了partition概念。

2、分割槽表指的是在建立表時指定的partition的分割槽空間。

3、如果需要建立有分割槽的表,需要在create表的時候呼叫可選引數partitioned by,詳見表建立的語法結構。

二、技術細節

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

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

3、分割槽是以欄位的形式在表結構中存在,通過describe table命令可以檢視到欄位存在,但是該欄位不存放實際的資料內容,僅僅是分割槽的表示。

4、建表的語法(建分割槽可參見PARTITIONED BY引數):

CREATE [EXTERNAL] TABLE [IF NOT EXISTS] table_name [(col_name data_type [COMMENT col_comment], ...)] [COMMENT table_comment] [PARTITIONED BY (col_name data_type [COMMENT col_comment], ...)] [CLUSTERED BY (col_name, col_name, ...) [SORTED BY (col_name [ASC|DESC], ...)] INTO num_buckets BUCKETS] [ROW FORMAT row_format] [STORED AS file_format] [LOCATION hdfs_path]

5、分割槽建表分為2種,一種是單分割槽,也就是說在表文件夾目錄下只有一級資料夾目錄。另外一種是多分割槽,表文件夾下出現多資料夾巢狀模式。

a、單分割槽建表語句:create table day_table (id int, content string) partitioned by (dt string);單分割槽表,按天分割槽,在表結構中存在id,content,dt三列。

b、雙分割槽建表語句:create table day_hour_table (id int, content string) partitioned by (dt string, hour string);雙分割槽表,按天和小時分割槽,在表結構中新增加了dt和hour兩列。

表文件夾目錄示意圖(多分割槽表):


6、新增分割槽表語法(表已建立,在此基礎上新增分割槽):

ALTER TABLE table_name ADD partition_spec [ LOCATION 'location1' ] partition_spec [ LOCATION 'location2' ] ... partition_spec: : PARTITION (partition_col = partition_col_value, partition_col = partiton_col_value, ...)

使用者可以用 ALTER TABLE ADD PARTITION 來向一個表中增加分割槽。當分割槽名是字串時加引號。例:

ALTER TABLE day_table ADD PARTITION (dt='2008-08-08', hour='08') location '/path/pv1.txt' PARTITION (dt='2008-08-08', hour='09') location '/path/pv2.txt';

7、刪除分割槽語法:

ALTER TABLE table_name DROP partition_spec, partition_spec,...

使用者可以用 ALTER TABLE DROP PARTITION 來刪除分割槽。分割槽的元資料和資料將被一併刪除。例:

ALTER TABLE day_hour_table DROP PARTITION (dt='2008-08-08', hour='09');

8、資料載入進分割槽表中語法:

LOAD DATA [LOCAL] INPATH 'filepath' [OVERWRITE] INTO TABLE tablename [PARTITION (partcol1=val1, partcol2=val2 ...)]

例:

LOAD DATA INPATH '/user/pv.txt' INTO TABLE day_hour_table PARTITION(dt='2008-08- 08', hour='08'); LOAD DATA local INPATH '/user/hua/*' INTO TABLE day_hour partition(dt='2010-07- 07');

當資料被載入至表中時,不會對資料進行任何轉換。Load操作只是將資料複製至Hive表對應的位置。資料載入時在表下自動建立一個目錄,檔案存放在該分割槽下。

9、基於分割槽的查詢的語句:

SELECT day_table.* FROM day_table WHERE day_table.dt>= '2008-08-08';

10、檢視分割槽語句:

hive> show partitions day_hour_table; OK dt=2008-08-08/hour=08 dt=2008-08-08/hour=09 dt=2008-08-09/hour=09

三、總結

1、在 Hive 中,表中的一個 Partition 對應於表下的一個目錄,所有的 Partition 的資料都儲存在最字集的目錄中。

2、總的說來partition就是輔助查詢,縮小查詢範圍,加快資料的檢索速度和對資料按照一定的規格和條件進行管理。

——————————————————————————————————————

hive中關於partition的操作:
hive> create table mp (a string) partitioned by (b string, c string);
OK
Time taken: 0.044 seconds
hive> alter table mp add partition (b='1', c='1');
OK
Time taken: 0.079 seconds
hive> alter table mp add partition (b='1', c='2');
OK
Time taken: 0.052 seconds
hive> alter table mp add partition (b='2', c='2');
OK
Time taken: 0.056 seconds
hive> show partitions mp ;
OK
b=1/c=1
b=1/c=2
b=2/c=2
Time taken: 0.046 seconds
hive> explain extended alter table mp drop partition (b='1');
OK
ABSTRACT SYNTAX TREE:
  (TOK_ALTERTABLE_DROPPARTS mp (TOK_PARTSPEC (TOK_PARTVAL b '1')))

STAGE DEPENDENCIES:
  Stage-0 is a root stage

STAGE PLANS:
  Stage: Stage-0
      Drop Table Operator:
        Drop Table
          table: mp


Time taken: 0.048 seconds
hive> alter table mp drop partition (b='1');
FAILED: Error in metadata: table is partitioned but partition spec is not specified or tab: {b=1}
FAILED: Execution Error, return code 1 from org.apache.hadoop.hive.ql.exec.DDLTask
hive> show partitions mp ;
OK
b=1/c=1
b=1/c=2
b=2/c=2
Time taken: 0.044 seconds
hive> alter table mp add   partition ( b='1', c = '3') partition ( b='1' , c='4');
OK
Time taken: 0.168 seconds
hive> show partitions mp ;
OK
b=1/c=1
b=1/c=2
b=1/c=3
b=1/c=4
b=2/c=2
b=2/c=3
Time taken: 0.066 seconds
hive>insert overwrite table mp partition (b='1', c='1') select cnt from tmp_et3 ;

hive>alter table mp add columns (newcol string);

location指定目錄結構
hive> alter table alter2 add partition (insertdate='2008-01-01') location '2008/01/01';

hive> alter table alter2 add partition (insertdate='2008-01-02') location '2008/01/02';