Apache Hive總結


作者:大數據學習與分享
鏈接:https://zhuanlan.zhihu.com/p/134122356

Apache Hive是基於Hadoop的一個數據倉庫工具,可以將結構化的數據文件映射為一張數據庫表,並提供一種HQL語言進行查詢,具有擴展性好、延展性好、高容錯等特點,多應用於離線數倉建設。

1. Hive架構

存儲:Hive底層存儲依賴於hdfs,因此也支持hdfs所支持的數據存儲格式,如text、json、parquet等。當我們將一個文件映射為Hive中一張表時,只需在建表時告訴Hive,數據中的列名、列分隔符、行分隔符等,Hive就可以自動解析數據。

支持多種壓縮格式:bzip2、gzip、lzo、snappy等。通常采用parquet+snappy格式存儲。支持計算引擎:原生支持引擎為MapReduce。但也支持其他計算引擎,如Spark、Tez。

元數據存儲:derby是Hive內置的元數據存儲庫,但是derby並發性能差且目前不支持多會話。實際生產中,更多的是采用mysql為Hive的元數據存儲庫。

HQL語句執行:解析器、編譯器、優化器完成HQL查詢語句從詞法分析、語法分析、編譯、優化以及查詢計划的生成。生成的查詢計划存儲在hdfs中,並在隨后轉化為MapReduce任務執行。

2.Hive的幾種建表方式

1)create [external] table ...
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];

create、if not exists等跟傳統的關系型數據庫含義類似,就不贅述了。筆者這里主要說一下hive建表時的幾個特殊關鍵字:

external:創建外部表時需要指定該關鍵字,並通過location指定數據存儲的路徑

partitioned by:創建分區表時,指定分區列。

clustered by和sort by:通常連用,用來創建分桶表,下文會具體闡述。

row format delimited [fields terminated by char] [collection items terminated by char] [map keys terminated by char] [lines terminated by char] serde serde_name [with serdeproperties (property_name=property_value, property_name=property_value, ...)]:指定行、字段、集合類型數據分割符、map類型數據key的分隔符等。用戶在建表的時候可以使用Hive自帶的serde或者自定義serde,Hive通過serde確定表具體列的數據。

stored as file_format:指定表數據存儲格式,如TextFile,SequenceFile,RCFile。默認textfile即文本格式,該方式支持通過load方式加載數據。如果數據需要壓縮,則采用sequencefile方式,但這種存儲方式不能通過load方式加載數據,必須從一個表中查詢出數據再寫入到一個表中insert overwrite table t1 select * from t1;

2) create table t_x as select ...即ctas語句,復制數據但不復制表結構,創建的為普通表。如果復制的是分區表則新創建的不是分區表但有分區字段。ctas語句是原子性的,如果select失敗,將不再執行create操作。

3) create table t_x like t_y  like允許用戶復制源表結構,但不復制數據。如,create table t2 like t1;

3.Hive的數據類型

Hive內置數據類型主要分為兩類:基礎數據類型和復雜數據類型。基礎數據類型無外乎就是tinyint、smallint、int、bigint、boolean、float、double、string、timestamp、decimal等,筆者這里主要介紹Hive的復雜數據類型,或者稱之為集合類型。

Hive的復雜數據類型主要分三種:map、array、struct,並且支持復雜類型嵌套,利用好這些數據類型,將有效提高數據查詢效率。目前為止對於關系型數據庫不支持這些復雜類型。

1.首先創建一張表

create table t_complex(id int, hobby1 map<string,string>, hobby2 array<string>, address struct<country:string,city:string>) row format delimited fields terminated by ',' collection items terminated by '-' map keys terminated by ':' ;

2.准備數據文件

1,唱歌:一般-跳舞:喜歡-游泳:不喜歡,唱歌-跳舞-游泳,USA-New York 2,打游戲:不喜歡-學習:非常喜歡,打游戲-籃球,CHINA-BeiJing

3.將數據文件load到創建的表中load data local inpath '/root/complex.txt' into table t_complex;

4.查詢map、array、struct類型數據查詢map和array跟java中是類似的,都是通過key查找map的value或者根據索引查找array中的元素,而struct則通過列名.標識來訪問元素。

查詢map示例:select hobby1['唱歌'] from t_complex;

查詢array示例:select hobby2[0], hobby2[1] from t_complex;

查詢struct示例:select address.country, address.city from t_complex;

4.內部表和外部表

Hive在創建表時默認創建的是內部表(又稱托管表)。當指定external關鍵字時,則創建的為外部表。並可以通過location指定建表的數據存儲的hdfs路徑。

Hive創建內部表時,會將數據復制/移動到數據倉庫指向的路徑;若創建外部表,僅記錄數據所在路徑,不對數據位置做任何改變。在刪除表時,內部表的元數據和表數據都會被刪除,而外部表只刪除元數據,不刪除表數據。

建議在生產中創建Hive表時采用外部表的方式,這樣在發生誤刪表的時,不至於把表數據也刪除,利於數據恢復和安全。當然也可以按照下述情況做細分處理:

1)所有數據處理,全部由hive完成,適合用內部表

2)有hive和其他工具共同處理一個數據集即同一數據集有多個應用要處理,適合用外部表

3)從hive中導出數據,供其他應用使用,適合用外部表

4)普遍用法:初始數據集由外部表操作,數據分析中間表使用內部表

5.order/sort/distribute/cluster by

order by:會將所有的數據匯聚到一個reduce上去執行,然后能保證全局有序。但是效率低,因為不能並行執行

sort by:當設置mapred.reduce.tasks>1,則sort by只保證每個reducer的輸出有序,不保證全局有序。好處是:執行了局部排序之后可以為接下去的全局排序提高不少的效率(其實就是做一次歸並排序就可以做到全局排序。

distribute by:根據指定的字段將數據分到不同的reduce,且分發算法是hash散列。能保證每一個reduce負責的數據范圍不重疊了,但是不保證排序的問題。

cluster by:除了具有distribute by的功能外,還會對該字段進行排序。

只有一個reduce時,cluster by效果不明顯,可以執行set mapred.reduce.tasks>1來使效果明顯。

當字段相同時,cluster by效果等同於distribute by+sort by。

注意:cluster 和 sort 在查詢(select)時不能共存,建表時可以共存

6. Hive中的分區、分桶以及數據抽樣

對Hive表進行分區、分桶,可以提高查詢效率,抽樣效率

6.1分區

分區,在hdfs中表現為table目錄下的子目錄

6.2分桶

對應建表時bucket關鍵字,在hdfs中表現為同一個表目錄下根據hash散列之后的多個文件,會根據不同的文件把數據放到不同的桶中。如果分桶表導入數據沒有生成對應數量的文件,可通過如下方式解決:

1.開啟自動分桶,設置參數:set hive.enforce.bucketing= true

2.手動設置reduce數量,比如set mapreduce.job.reduces=4。建議對於設計表有分桶需求時,開啟自動分桶。因為一旦reduce數量設置錯了,規划的分桶數會無效。

注意:要用insert語句或者ctas語句將數據存入分桶表。load語句只是文件的移動或復制。

6.3 抽樣(sampling)

6.3.1 按塊抽樣

1)百分比

select * from some_table tablesample(40 percent);

2)按大小

select * from some_table tablesample(20M);

3)按照行數取樣

select * from some_table tablesample(1000 rows);

6.3.2 按桶抽樣

其實就是對分桶表進行抽樣,效率高。

抽樣數據量=總數據量/抽樣分桶數。

示例:select count(1) from tableA Tablesample(bucket 2 out of 8 on user_id);即Tablesample(bucket 開始取樣的桶 out of 分成多少個桶)。

如果要進行抽樣,建議:

1.如果提前分桶了,表分桶數與抽樣分桶數一致,那么只會掃描那個指定桶的數據

2.如果預先分桶和抽樣分桶數不一致:重新分桶

3.如果沒分桶:先分桶,在抽樣

7.Hive的嚴格模式和非嚴格模式

通過設置參數hive.mapred.mode來設置是否開啟嚴格模式。目前參數值有兩個:strict(嚴格模式)和nostrict(非嚴格模式,默認)。通過開啟嚴格模式,主要是為了禁止某些查詢(這些查詢可能造成意想不到的壞的結果),目前主要禁止3種類型的查詢:

1)分區表查詢在查詢一個分區表時,必須在where語句后指定分區字段,否則不允許執行。

因為在查詢分區表時,如果不指定分區查詢,會進行全表掃描。而分區表通常有非常大的數據量,全表掃描非常消耗資源。

2)order by 查詢order by語句必須帶有limit 語句,否則不允許執行。

因為order by會進行全局排序,這個過程會將處理的結果分配到一個reduce中進行處理,處理時間長且影響性能。

3)笛卡爾積查詢數據量非常大時,笛卡爾積查詢會出現不可控的情況,因此嚴格模式下也不允許執行。

在開啟嚴格模式下,進行上述三種不符合要求的查詢,通常會報類似FAILED: Error in semantic analysis: In strict mode, XXX is not allowed. If you really want to perform the operation,+set hive.mapred.mode=nonstrict+

8.Hive JOIN

寫join查詢時,需要注意幾個關鍵點:1)只支持等值join,因為非等值連接非常難轉化為MapReduce任務

示例:select a.* from a join b on a.id = b.id是正確的,然而:select a.* from a join b on a.id>b.id是錯誤的。

2)可以join多個表,如果join中多個表的join的列是同一個,則join會被轉化為單個MapReduce任務示例:select a.*, b.*, c.* from a join b on a.col= b.col1 join c on c.col= b.col1被轉化為單個MapReduce任務,因為join中只使用了b.col1作為join列。

但是如下寫法會被轉化為2個MapReduce任務。因為 b.col1用於第一次join條件,而 b.col2用於第二次 join

select a.*, b.*, c.* from a join b on a.col= b.col1 join c on c.col= b.col2;

3)join時,轉換為MapReduce任務的邏輯

reduce會緩存join序列中除了最后一個表的所有表的記錄(具體看啟動了幾個map/reduce任務),再通過最后一個表將結果序列化到文件系統。這一實現有助於在reduce端減少內存的使用量。實踐中,應該把最大的那個表寫在最后(否則會因為緩存浪費大量內存)。示例:a.單個map/reduce任務select a.*, b.*, c.* from a join b on a.col= b.col1 join c on c.col= b.col1中所有表都使用同一個join列。reduce端會緩存a表和b表的記錄,然后每次取得一個c表的記錄就計算一次join結果;b.多個map/reduce任務

select a.*, b.*, c.* from a join b on (a.col= b.col1) join c on (c.col= b.col2)。第一次緩存a表,用b表序列化;第二次緩存第一次MapReduce任務的結果,然后用c表序列化。

4)left semi join

經常用來替換 in和exists。

如,select * from a left semi join b on a.id = b.id; 相當於select * from a where a.id exists(select b.id from b);但這種方式在hive中效率極低。

9.Hive中的3種虛擬列

當Hive產生非預期的數據或null時,可以通過虛擬列進行診斷,判斷哪行數據出現問題,主要分3種:

1.INPUT__FILE__NAME

每個map任務輸入文件名

2.BLOCK__OFFSET__INSIDE__FILE

map任務處理的數據所對應文件的塊內偏移量,當前全局文件的偏移量。對於塊壓縮文件,就是當前塊的文件偏移量,即當前塊的第一個字節在文件中的偏移量

3.ROW__OFFSET__INSIDE__BLOCK行偏移量,默認不可用。需要設置hive.exec.rowoffset=true來啟用

10.Hive條件判斷

Hive中可能會遇到根據判斷不同值,產生對應結果的場景,有三種實現方式:if、coalesce、case when。

1.if( condition, true value, false value)只能用來判斷單個條件。

示例:select if(col_name='張三',1,0) as x from tab;

2.coalesce( value1,value2,… )獲取參數列表中的首個非空值,若均為null,則返回null。

示例select coalesce(null,null,5,null,1,0) as x; 返回5

3.case when

可以與某字段多個比較值的判斷,並分別產生不同結果,與其他語言中case語法相似。

select

case col_name when "張三" then 1 when "李四" then 0

else 2 end as x from tab; 或: select

case when col_name="張三" then 1 when col_name="李四" then 0

else 2 end as x from tab;

11.Hive與傳統的關系型數據庫對比




免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM