1. 程式人生 > >hive的三板斧:內部表和外部表、分割槽和分桶以及序列化/反序列化(SerDe)

hive的三板斧:內部表和外部表、分割槽和分桶以及序列化/反序列化(SerDe)

hive的三板斧:內部表和外部表、分割槽和分桶以及序列化/反序列化(SerDe)

 

Hive是Hadoop生態圈中實現資料倉庫的一項技術。雖然Hadoop和HDFS的設計侷限了Hive所能勝任的工作,但是Hive仍然是目前網際網路中最適合資料倉庫的應用技術。 不論從“品相還是舉止”,Hive都像一個關係型資料庫。使用者對資料庫、表和列這類術語比較熟悉的話,那麼掌握Hive的查詢語言HQL也輕而易舉。不過,Hive的實現和使用方式與傳統的關係資料庫相比,有很多不同的地方。

我們Hive的第一篇文章就將講到Hive數倉中模式設計的三板斧:內部表和外部表、分割槽和分桶以及序列化/反序列化(SerDe)。

一. 內部表和外部表

Hive將資料表分為內部表和外部表。

內部表

在Hive中建立的普通表都可稱作“內部表”。因為Hive可以(或多或少)控制其資料的生命週期,內部表對資料擁有所有權。如我們所見,通常Hive會將內部表的資料儲存在由hive.metastore.warehouse.dir所定義的目錄下。

所以,當刪除一個內部表時,相應的資料也會被刪除。

外部表

內部表不方便共享資料來源。例如,當採用如Pig或MapReduce等技術工具進行資料處理時,我們將無法讀取內部表的資料,也不能將外部資料直接作為內部表資料來源分享給Hive。這樣的需求就誕生了外部表。不同於內部表,Hive 對外部表的資料僅僅擁有使用權,而資料位置可由表管理者任意配置。

如何理解外部表呢?

如圖所示,外部表不需要將資料複製到Hive中。一旦關聯上資料格式和資料位置,Hive就能直接訪問外部資料,非常靈活方便,即插即用。

而載入內部表資料時,Hive會自動將源資料拷貝到內部。內部表其實訪問的是資料副本。

注意,Hive載入內部表資料後會把資料來源刪除,很像"剪下/移動"。所以,往內部表上傳資料時,千萬記得備份!

二. 分割槽和分桶分割槽

對於大型資料處理系統而言,資料分割槽的功能是非常重要的。因為Hive通常要對資料進行全盤掃描,才能滿足查詢條件(我們暫時先忽略索引的功能)。

以Hive管理大型網站的瀏覽日誌為例。如果日誌資料表不採用分割槽設計,那麼就單日網站流量分析這樣的需求而言,Hive就必然要通過遍歷全量日誌來完成查詢。以一年日誌為全量,單日查詢的資料利用率將不到1%,這樣的設計基本上將查詢時間浪費在了資料載入中。

分割槽的優勢在於利用維度分割資料。在使用分割槽維度查詢時,Hive只需要載入資料,極大縮短資料載入時間。上述案例中,假使我們以日期為維度設計日誌資料表的分割槽,對於自選日期範圍的查詢需求,Hive就只需載入日期範圍所對應的分割槽資料。

由於HDFS被設計用於儲存大型資料檔案而非海量碎片檔案,理想的分割槽方案不應該導致過多的分割槽檔案,並且每個目錄下的檔案儘量超過HDFS塊大小的若干倍。按天級時間粒度進行分割槽就是一個好的分割槽策略,隨著時間的推移,分割槽數量增長均勻可控。此外常有的分割槽策略還有地域,語言種類等等。設計分割槽的時候,還有一個誤區需要避免。關於分割槽維度的選擇,我們應該儘量選取那些有限且少量的數值集作為分割槽,例如國家、省份就是一個良好的分割槽,而城市就可能不適合進行分割槽。

注意:分割槽是資料表中的一個列名,但是這個列並不佔有表的實際儲存空間。它作為一個虛擬列而存在。

分桶

分割槽提供了一種整理資料和優化查詢的便利方式。不過,並非所有資料集都可形成合理的分割槽,特別是在需要合理劃分資料、防止傾斜時。分桶是將資料分解管理的另一技術。

假設我們有一張地域姓名錶並按城市分割槽。那麼很有可能,北京分割槽的人數會遠遠大於其他分割槽,該分割槽的資料I/O吞吐效率將成為查詢的瓶頸。如果我們對錶中的姓名做分桶,將姓名按雜湊值分發到桶中,每個桶將分配到大致均勻的人數。

分桶解決的是資料傾斜的問題。因為桶的數量固定,所以沒有資料波動。桶對於資料抽樣再適合不過,同時也有利於高效的map-side Join。

分桶與分割槽的關係

  • 分割槽和分桶都可以單獨用於表;
  • 分割槽可以是多級的;
  • 分割槽和分桶可以巢狀使用,但是分割槽必須在分桶前面。

三. 序列化/反序列化(SerDe)

如果說前兩者分別是Hive模式設計的沙漠飛鷹和AK47,那麼SerDe就是巡航導彈。

下面我們來看一下SerDe是什麼。

SerDe是序列化/反序列化的簡寫形式,其作用是將一條非結構化位元組轉化成Hive可以使用的一條記錄。Hive本身自帶了幾個內建的SerDe,而一些第三方的SerDe也十分常用。

我們舉例介紹一下常見SerDe:

  • RegexSerDe
  • CSVSerde/TSVSerde
  • JsonSerde
  • AvroSerDe
  • LazySimpleSerDe
  • ......

以JsonSerde為例,

本例中,/data/messages檔案為Json格式。JsonSerde讀取messages中的每一條記錄,並解析成Json Object,在程式碼中以$表示。類似"msg_id"="$.id"這樣的操作語句,表示獲取$["id"]的資料內容並轉化成messages中的msg_id。

一旦定義好之後,使用者就不再需要關心如何讀取解析Json資料,可以像操作資料庫資料一樣操作Json資料。

serdeproperties是Hive提供給SerDe的一個功能,Hive並不關心這些配置屬性是什麼。在讀取檔案記錄的時候,SerDe讀取相應的配置資訊來完成解析工作。也就是說,serdeproperties其實是SerDe的配置介面,一種SerDe擁有一種配置資訊格式,而不同SerDe之間的serdeproperties配置資訊並沒有任何關聯。下圖為SerDe的工作原理,

Hive的SerDe著實是一項重磅武器。對於絕對大多數常用的資料格式,Hive官方或者第三方都提供了相應的SerDe。如果有公司和團隊劍走偏鋒,採用一些“非凡”的資料格式,仍然可以自定義SerDe。

例如,友盟的移動APP日誌資料就採用Google Protobuf格式,並選用高壓縮比的lzma/lzo作為壓縮演算法,而Hive原生態元件中並不支援解析這樣的資料格式。如果將Protobuf+lzo的資料轉化成文字或者Json以方便Hive讀取,又將面臨大量的資料冗餘。友盟資料倉庫搭建採用了Twitter開源專案ElephantBird提供的“ProtobufDeserializer”,又在此基礎上實現了對lzo/lzma的解壓縮功能,無縫地對接上了友盟資料平臺的離線日誌。 友盟的小夥伴們從此走上了幸福而快樂的資料分析之路。