1、Hive架構與基本組成
下面是Hive的架構圖。
圖1.1 Hive體系結構
Hive的體系結構可以分爲以下幾部分:
(1)用戶接口主要有三個:CLI,Client 和 WUI。其中最常用的是CLI,Cli啓動的時候,會同時啓動一個Hive副本。Client是Hive的客戶端,用戶連接至Hive Server。在啓動 Client模式的時候,需要指出Hive Server所在節點,並且在該節點啓動Hive Server。 WUI是通過瀏覽器訪問Hive。
(2)Hive將元數據存儲在數據庫中,如mysql、derby。Hive中的元數據包括表的名字,表的列和分區及其屬性,表的屬性(是否爲外部表等),表的數據所在目錄等。
(3)解釋器、編譯器、優化器完成HQL查詢語句從詞法分析、語法分析、編譯、優化以及查詢計劃的生成。生成的查詢計劃存儲在HDFS中,並在隨後有MapReduce調用執行。
(4)Hive的數據存儲在HDFS中,大部分的查詢、計算由MapReduce完成(包含*的查詢,比如select * from tbl不會生成MapRedcue任務)。
Hive將元數據存儲在RDBMS中,
有三種模式可以連接到數據庫:
(1) 單用戶模式。此模式連接到一個In-memory 的數據庫Derby,一般用於Unit Test。
圖2.1 單用戶模式
(2)多用戶模式。通過網絡連接到一個數據庫中,是最經常使用到的模式。
圖2.2 多用戶模式
(3) 遠程服務器模式。用於非Java客戶端訪問元數據庫,在服務器端啓動MetaStoreServer,客戶端利用Thrift協議通過MetaStoreServer訪問元數據庫。
對於數據存儲,Hive沒有專門的數據存儲格式,也沒有爲數據建立索引,用戶可以非常自由的組織Hive中的表,只需要在創建表的時候告訴Hive數據中的列分隔符和行分隔符,Hive就可以解析數據。Hive中所有的數據都存儲在HDFS中,存儲結構主要包括數據庫、文件、表和視圖。Hive中包含以下數據模型:Table內部表,External Table外部表,Partition分區,Bucket桶。Hive默認可以直接加載文本文件,還支持sequence file 、RCFile。
Hive的數據模型介紹如下:
(1)Hive數據庫
類似傳統數據庫的DataBase,在第三方數據庫裏實際是一張表。簡單示例命令行 hive > create database test_database;
(2)內部表
Hive的內部表與數據庫中的Table在概念上是類似。每一個Table在Hive中都有一個相應的目錄存儲數據。例如一個表pvs,它在HDFS中的路徑爲/wh/pvs,其中wh是在hive-site.xml中由${hive.metastore.warehouse.dir} 指定的數據倉庫的目錄,所有的Table數據(不包括External Table)都保存在這個目錄中。刪除表時,元數據與數據都會被刪除。
內部表簡單示例:
創建數據文件:test_inner_table.txt
創建表:create table test_inner_table (key string)
加載數據:LOAD DATA LOCAL INPATH ‘filepath’ INTO TABLE test_inner_table
查看數據:select * from test_inner_table; select count(*) from test_inner_table
刪除表:drop table test_inner_table
(3)外部表
外部表指向已經在HDFS中存在的數據,可以創建Partition。它和內部表在元數據的組織上是相同的,而實際數據的存儲則有較大的差異。內部表的創建過程和數據加載過程這兩個過程可以分別獨立完成,也可以在同一個語句中完成,在加載數據的過程中,實際數據會被移動到數據倉庫目錄中;之後對數據對訪問將會直接在數據倉庫目錄中完成。刪除表時,表中的數據和元數據將會被同時刪除。而外部表只有一個過程,加載數據和創建表同時完成(CREATE
EXTERNAL TABLE ……LOCATION),實際數據是存儲在LOCATION後面指定的 HDFS 路徑中,並不會移動到數據倉庫目錄中。當刪除一個External Table時,僅刪除該鏈接。
外部表簡單示例:
創建數據文件:test_external_table.txt
創建表:create external table test_external_table (key string)
加載數據:LOAD DATA INPATH ‘filepath’ INTO TABLE test_inner_table
查看數據:select * from test_external_table; •select count(*) from test_external_table
刪除表:drop table test_external_table
(4)分區
Partition對應於數據庫中的Partition列的密集索引,但是Hive中Partition的組織方式和數據庫中的很不相同。在Hive中,表中的一個Partition對應於表下的一個目錄,所有的Partition的數據都存儲在對應的目錄中。例如pvs表中包含ds和city兩個Partition,則對應於ds = 20090801, ctry = US 的HDFS子目錄爲/wh/pvs/ds=20090801/ctry=US;對應於 ds = 20090801, ctry = CA 的HDFS子目錄爲/wh/pvs/ds=20090801/ctry=CA。
分區表簡單示例:
創建數據文件:test_partition_table.txt
創建表:create table test_partition_table (key string) partitioned by (dt string)
加載數據:LOAD DATA INPATH ‘filepath’ INTO TABLE test_partition_table partition (dt=‘2006’)
查看數據:select * from test_partition_table; select count(*) from test_partition_table
刪除表:drop table test_partition_table
(5)桶
Buckets是將表的列通過Hash算法進一步分解成不同的文件存儲。它對指定列計算hash,根據hash值切分數據,目的是爲了並行,每一個Bucket對應一個文件。例如將user列分散至32個bucket,首先對user列的值計算hash,對應hash值爲0的HDFS目錄爲/wh/pvs/ds=20090801/ctry=US/part-00000;hash值爲20的HDFS目錄爲/wh/pvs/ds=20090801/ctry=US/part-00020。如果想應用很多的Map任務這樣是不錯的選擇。
桶的簡單示例:
創建數據文件:test_bucket_table.txt
創建表:create table test_bucket_table (key string) clustered by (key) into 20 buckets
加載數據:LOAD DATA INPATH ‘filepath’ INTO TABLE test_bucket_table
查看數據:select * from test_bucket_table; set hive.enforce.bucketing = true;
(6)Hive的視圖
視圖與傳統數據庫的視圖類似。視圖是隻讀的,它基於的基本表,如果改變,數據增加不會影響視圖的呈現;如果刪除,會出現問題。•如果不指定視圖的列,會根據select語句後的生成。
示例:create view test_view as select * from test
2、Hive的執行原理
圖2.1 Hive的執行原理
Hive構建在Hadoop之上,
(1)HQL中對查詢語句的解釋、優化、生成查詢計劃是由Hive完成的
(2)所有的數據都是存儲在Hadoop中
(3)查詢計劃被轉化爲MapReduce任務,在Hadoop中執行(有些查詢沒有MR任務,如:select * from table)
(4)Hadoop和Hive都是用UTF-8編碼的
Hive編譯器將一個Hive QL轉換操作符。操作符Operator是Hive的最小的處理單元,每個操作符代表HDFS的一個操作或者一道MapReduce作業。Operator都是hive定義的一個處理過程,其定義有:
protected List <Operator<? extends Serializable >> childOperators;
protected List <Operator<? extends Serializable >> parentOperators;
protected boolean done; // 初始化值爲false
所有的操作構成了Operator圖,hive正是基於這些圖關係來處理諸如limit, group by, join等操作。
圖2.2 Hive QL的操作符
操作符如下:
TableScanOperator:掃描hive表數據
ReduceSinkOperator:創建將發送到Reducer端的<Key,Value>對
JoinOperator:Join兩份數據
SelectOperator:選擇輸出列
FileSinkOperator:建立結果數據,輸出至文件
FilterOperator:過濾輸入數據
GroupByOperator:GroupBy語句
MapJoinOperator:/*+mapjoin(t) */
LimitOperator:Limit語句
UnionOperator:Union語句
Hive通過ExecMapper和ExecReducer執行MapReduce任務。在執行MapReduce時有兩種模式,即本地模式和分佈式模式 。
Hive編譯器的組成:
圖2.3 Hive編譯器的組成
編譯流程如下:
圖2.4 Hive QL編譯流程
3、Hive和數據庫的異同
由於Hive採用了SQL的查詢語言HQL,因此很容易將Hive理解爲數據庫。其實從結構上來看,Hive和數據庫除了擁有類似的查詢語言,再無類似之處。數據庫可以用在Online的應用中,但是Hive是爲數據倉庫而設計的,清楚這一點,有助於從應用角度理解Hive的特性。
Hive和數據庫的比較如下表:
(1)查詢語言。由於 SQL 被廣泛的應用在數據倉庫中,因此專門針對Hive的特性設計了類SQL的查詢語言HQL。熟悉SQL開發的開發者可以很方便的使用Hive進行開發。
(2)數據存儲位置。Hive是建立在Hadoop之上的,所有Hive的數據都是存儲在HDFS中的。而數據庫則可以將數據保存在塊設備或者本地文件系統中。
(3)數據格式。Hive中沒有定義專門的數據格式,數據格式可以由用戶指定,用戶定義數據格式需要指定三個屬性:列分隔符(通常爲空格、”\t”、”\x001″)、行分隔符(”\n”)以及讀取文件數據的方法(Hive中默認有三個文件格式TextFile,SequenceFile以及RCFile)。由於在加載數據的過程中,不需要從用戶數據格式到Hive定義的數據格式的轉換,因此,
Hive在加載的過程中不會對數據本身進行任何修改,而只是將數據內容複製或者移動到相應的HDFS目錄中。
而在數據庫中,不同的數據庫有不同的存儲引擎,定義了自己的數據格式。所有數據都會按照一定的組織存儲,因此,數據庫加載數據的過程會比較耗時。
(4)數據更新。由於Hive是針對數據倉庫應用設計的,而數據倉庫的內容是讀多寫少的。因此,Hive中不支持對數據的改寫和添加,所有的數據都是在加載的時候中確定好的。而數據庫中的數據通常是需要經常進行修改的,因此可以使用INSERT INTO ... VALUES添加數據,使用UPDATE ... SET修改數據。
(5)索引。之前已經說過,Hive在加載數據的過程中不會對數據進行任何處理,甚至不會對數據進行掃描,因此也沒有對數據中的某些Key建立索引。Hive要訪問數據中滿足條件的特定值時,需要暴力掃描整個數據,因此訪問延遲較高。由於MapReduce的引入, Hive可以並行訪問數據,因此即使沒有索引,對於大數據量的訪問,Hive仍然可以體現出優勢。數據庫中,通常會針對一個或者幾個列建立索引,因此對於少量的特定條件的數據的訪問,數據庫可以有很高的效率,較低的延遲。由於數據的訪問延遲較高,決定了Hive不適合在線數據查詢。
(6)執行。Hive中大多數查詢的執行是通過Hadoop提供的MapReduce來實現的(類似select * from tbl的查詢不需要MapReduce)。而數據庫通常有自己的執行引擎。
(7)執行延遲。之前提到,Hive在查詢數據的時候,由於沒有索引,需要掃描整個表,因此延遲較高。另外一個導致Hive執行延遲高的因素是MapReduce框架。由於MapReduce本身具有較高的延遲,因此在利用MapReduce執行Hive查詢時,也會有較高的延遲。相對的,數據庫的執行延遲較低。當然,這個低是有條件的,即數據規模較小,當數據規模大到超過數據庫的處理能力的時候,Hive的並行計算顯然能體現出優勢。
(8)可擴展性。由於Hive是建立在Hadoop之上的,因此Hive的可擴展性是和Hadoop的可擴展性是一致的(世界上最大的Hadoop集羣在Yahoo!,2009年的規模在4000臺節點左右)。而數據庫由於ACID語義的嚴格限制,擴展行非常有限。目前最先進的並行數據庫Oracle在理論上的擴展能力也只有100臺左右。
(9)數據規模。由於Hive建立在集羣上並可以利用MapReduce進行並行計算,因此可以支持很大規模的數據;對應的,數據庫可以支持的數據規模較小。
4、Hive元數據庫
Hive將元數據存儲在RDBMS 中,一般常用的有MYSQL和DERBY。
啓動HIVE的元數據庫時,需要進入到hive的安裝目錄
啓動derby數據庫:/home/admin/caona/hive/build/dist/,運行startNetworkServer -h 0.0.0.0。
連接Derby數據庫進行測試:查看/home/admin/caona/hive/build/dist/conf/hive-default.xml。找到
-
-
<P style="TEXT-ALIGN: left; PADDING-BOTTOM: 0px; WIDOWS: 2; TEXT-TRANSFORM: none; BACKGROUND-COLOR: rgb(255,255,255); TEXT-INDENT: 0px; MARGIN: 0px; PADDING-LEFT: 0px; PADDING-RIGHT: 0px; FONT: 14px/26px Arial; WHITE-SPACE: normal; ORPHANS: 2; LETTER-SPACING:
normal; COLOR: rgb(0,0,0); WORD-SPACING: 0px; PADDING-TOP: 0px; -webkit-text-size-adjust: auto; -webkit-text-stroke-width: 0px"> </P>
複製代碼
進入derby安裝目錄:/home/admin/caona/hive/build/dist/db-derby-10.4.1.3-bin/bin
輸入:./ij Connect 'jdbc:derby://hadoop1:1527/metastore_db;create=true';
hive元數據對應的表約有20個,其中和表結構信息有關的有9張,其餘的10多張或爲空,或只有簡單的幾條記錄,以下是部分主要表的簡要說明。
表名 |
說明 |
關聯鍵 |
TBLS |
所有hive表的基本信息 |
TBL_ID,SD_ID |
TABLE_PARAM |
表級屬性,如是否外部表,表註釋等 |
TBL_ID |
COLUMNS |
Hive表字段信息(字段註釋,字段名,字段類型,字段序號) |
SD_ID |
SDS |
所有hive表、表分區所對應的hdfs數據目錄和數據格式 |
SD_ID,SERDE_ID |
SERDE_PARAM |
序列化反序列化信息,如行分隔符、列分隔符、NULL的表示字符等 |
SERDE_ID |
PARTITIONS |
Hive表分區信息 |
PART_ID,SD_ID,TBL_ID |
PARTITION_KEYS |
Hive分區表分區鍵 |
TBL_ID |
PARTITION_KEY_VALS |
Hive表分區名(鍵值) |
PART_ID |
從上面表的內容來看,hive整個創建表的過程已經比較清楚了。 (1)解析用戶提交hive語句,對其進行解析,分解爲表、字段、分區等hive對象 (2)根據解析到的信息構建對應的表、字段、分區等對象,從 SEQUENCE_TABLE中獲取構建對象的最新ID,與構建對象信息(名稱,類型等)一同通過DAO方法寫入到元數據表中去,成功後將SEQUENCE_TABLE中對應的最新ID+5。 實際上我們常見的RDBMS都是通過這種方法進行組織的,典型的如postgresql,其系統表中和hive元數據一樣裸露了這些id信息(oid,cid等),而Oracle等商業化的系統則隱藏了這些具體的ID。通過這些元數據我們可以很容易的讀到數據諸如創建一個表的數據字典信息,比如導出建表語名等。
5、Hive基本操作
Create Table語句的一些注意項:
(1)CREATE TABLE創建一個指定名字的表。如果相同名字的表已經存在,則拋出異常;用戶可以用IF NOT EXIST選項來忽略這個異常。
(2)EXTERNAL 關鍵字可以讓用戶創建一個外部表,在建表的同時指定一個指向實際數據的路徑( LOCATION ),Hive 創建內部表時,會將數據移動到數據倉庫指向的路徑;若創建外部表,僅記錄數據所在的路徑,不對數據的位置做任何改變。在刪除表的時候,內部表的元數據和數據會被一起刪除,而外部表只刪除元數據,不刪除數據。
(3)LIKE允許用戶複製現有的表結構,但是不復制數據。
(4)用戶在建表的時候可以自定義SerDe或者使用自帶的 SerDe ( Serialize/Deserilize 的簡稱,目的是用於序列化和反序列化 )。如果沒有指定 ROW FORMAT 或者 ROW FORMAT DELIMITED,將會使用自帶的SerDe。在建表的時候,用戶還需要爲表指定列,用戶在指定表的列的同時也會指定自定義的SerDe,Hive通過SerDe確定表的具體的列的數據。
(5)如果文件數據是純文本,可以使用STORED AS TEXTFILE。如果數據需要壓縮,使用STORED AS SEQUENCE。
(6)有分區的表可以在創建的時候使用 PARTITIONED B Y語句。一個表可以擁有一個或者多個分區,每一個分區單獨存在一個目錄下。而且,表和分區都可以對某個列進行CLUSTERED BY操作,將若干個列放入一個桶(bucket)中。也可以利用SORT BY對數據進行排序。這樣可以爲特定應用提高性能。
(7)表名和列名不區分大小寫,SerDe和屬性名區分大小寫。表和列的註釋是字符串。
Alter Table語句:主要功能包括Add Partitions, Drop Partitions, Rename Table, Change Column, Add/Replace Columns。
Create View語句:創建視圖。格式CREATE VIEW [IF NOT EXISTS] view_name [ (column_name [COMMENT column_comment], ...) ]
Showy語句:Show tables; Show partitions; describe查看錶結構。
Load語句:HIVE裝載數據時沒有做任何轉換,加載到表中的數據只是進入相應的配置單元表的位置。Load操作只是單純的複製/移動操作,將數據文件移動到Hive表對應的位置。
Insert語句:插入數據。Hive不支持一條一條的用 insert 語句進行插入操作,這個應該是與hive的storage layer是有關係的,因爲它的存儲層是HDFS,插入一個數據要全表掃描,還不如用整個表的替換來的快些。Hive也不支持update的操作。數據是以load的方式,加載到建立好的表中。數據一旦導入,則不可修改。要麼drop掉整個表,要麼建立新的表,導入新的數據。
Drop語句:刪除一個內部表的同時會同時刪除表的元數據和數據。刪除一個外部表,只刪除元數據而保留數據。
Limit子句:可以限制查詢的記錄數。查詢的結果是隨機選擇的。下面的查詢語句從 t1 表中隨機查詢5條記錄,SELECT * FROM t1 LIMIT 5。
Top K查詢:下面的查詢語句查詢銷售記錄最大的 5 個銷售代表。
SET mapred.reduce.tasks = 1
SELECT * FROM sales SORT BY amount DESC LIMIT 5
正則表達式使用:SELECT語句可以使用正則表達式做列選擇,下面的語句查詢除了ds和h 之外的所有列:
SELECT `(ds|hr)?+.+` FROM sales
SELECT語句:查詢數據。
Group by, Order by, Sort by子句:聚合可進一步分爲多個表,甚至發送到 Hadoop 的 DFS 的文件(可以進行操作,然後使用HDFS的utilitites)。可以用hive.map.aggr控制怎麼進行彙總。默認爲爲true,配置單元會做的第一級聚合直接在MAP上的任務。這通常提供更好的效率,但可能需要更多的內存來運行成功。
Join語句:連接操作。一些注意事項:
(1)Hive只支持等值連接(equality joins)、外連接(outer joins)和(left/right joins)。Hive不支持所有非等值的連接,因爲非等值連接非常難轉化到map/reduce任務。
(2)Hive 支持多於2個表的連接。
(3)join 時,每次 map/reduce 任務的邏輯: reducer 會緩存 join 序列中除了最後一個表的所有表的記錄, 再通過最後一個表將結果序列化到文件系統。這一實現有助於在reduce端減少內存的使用量。實踐中,應該把最大的那個表寫在最後(否則會因爲緩存浪費大量內存)。
(4)LEFT,RIGHT 和 FULL OUTER 關鍵字用於處理 join 中空記錄的情況。
(5)LEFT SEMI JOIN 是 IN/EXISTS 子查詢的一種更高效的實現。Hive 當前沒有實現 IN/EXISTS 子查詢,所以你可以用 LEFT SEMI JOIN 重寫你的子查詢語句。LEFT SEMI JOIN的限制是, JOIN子句中右邊的表只能在ON子句中設置過濾條件,在WHERE子句、SELECT子句或其他地方過濾都不行。
6、使用HIVE注意點
(1)字符集
Hadoop和Hive都是用UTF-8編碼的,所以, 所有中文必須是UTF-8編碼, 才能正常使用。
備註:中文數據load到表裏面,,如果字符集不同,很有可能全是亂碼需要做轉碼的,但是hive本身沒有函數來做這個。
(2)壓縮
hive.exec.compress.output 這個參數,默認是false,但是很多時候貌似要單獨顯式設置一遍,否則會對結果做壓縮的,如果你的這個文件後面還要在hadoop下直接操作,那麼就不能壓縮了。
(3)count(distinct)
當前的Hive不支持在一條查詢語句中有多Distinct。如果要在Hive查詢語句中實現多Distinct,需要使用至少n+1條查詢語句(n爲distinct的數目),前n條查詢分別對n個列去重,最後一條查詢語句對n個去重之後的列做Join操作,得到最終結果。
(4)JOIN
只支持等值連接
(5)DML操作
只支持INSERT/LOAD操作,無UPDATE和DELTE
(6)HAVING
不支持HAVING操作。如果需要這個功能要嵌套一個子查詢用where限制
(7)子查詢
Hive不支持where子句中的子查詢
(8)Join中處理null值的語義區別
SQL標準中,任何對null的操作(數值比較,字符串操作等)結果都爲null。Hive對null值處理的邏輯和標準基本一致,除了Join時的特殊邏輯。這裏的特殊邏輯指的是,Hive的Join中,作爲Join key的字段比較,null=null是有意義的,且返回值爲true。
(9)分號字符
分號是SQL語句結束標記,在HiveQL中也是,但是在HiveQL中,對分號的識別沒有那麼智慧,例如:
select concat(cookie_id,concat(';',’zoo’)) from c02_clickstat_fatdt1 limit 2;
FAILED: Parse Error: line 0:-1 cannot recognize input '<EOF>' in function specification
可以推斷,Hive解析語句的時候,只要遇到分號就認爲語句結束,而無論是否用引號包含起來。
解決的辦法是,使用分號的八進制的ASCII碼進行轉義,那麼上述語句應寫成:
select concat(cookie_id,concat('\073','zoo')) from c02_clickstat_fatdt1 limit 2;
爲什麼是八進制ASCII碼?我嘗試用十六進制的ASCII碼,但Hive會將其視爲字符串處理並未轉義,好像僅支持八進制,原因不詳。這個規則也適用於其他非SELECT語句,如CREATE TABLE中需要定義分隔符,那麼對不可見字符做分隔符就需要用八進制的ASCII碼來轉義。
(10)Insert
根據語法Insert必須加“OVERWRITE”關鍵字,也就是說每一次插入都是一次重寫。
7、Hive的擴展特性
Hive 是一個很開放的系統,很多內容都支持用戶定製,包括:
* 文件格式:Text File,Sequence File
* 內存中的數據格式: Java Integer/String, Hadoop IntWritable/Text
* 用戶提供的map/reduce腳本:不管什麼語言,利用stdin/stdout傳輸數據
* 用戶自定義函數:Substr, Trim, 1 – 1
* 用戶自定義聚合函數:Sum, Average…… n – 1
(1)數據文件格式
|
TextFile |
SequenceFIle |
RCFFile |
Data type |
Text Only |
Text/Binary |
Text/Binary |
Internal Storage Order |
Row-based |
Row-based |
Column-based |
Compression |
File Based |
Block Based |
Block Based |
Splitable |
YES |
YES |
YES |
Splitable After Compression |
No |
YES |
YES |
例如使用文件文件格式存儲創建的表:
-
CREATE TABLE mylog ( user_id BIGINT, page_url STRING, unix_time INT)
-
STORED AS TEXTFILE;
複製代碼
當用戶的數據文件格式不能被當前Hive所識別的時候,可以自定義文件格式。可以參考contrib/src/java/org/apache/hadoop/hive/contrib/fileformat/base64中的例子。寫完自定義的格式後,在創建表的時候指定相應的文件格式就可以:
-
CREATE TABLE base64_test(col1 STRING, col2 STRING)
-
STORED AS
-
INPUTFORMAT 'org.apache.hadoop.hive.contrib.
-
fileformat.base64.Base64TextInputFormat'
-
OUTPUTFORMAT 'org.apache.hadoop.hive.contrib.
-
fileformat.base64.Base64TextOutputFormat';
複製代碼
(2)SerDe
SerDe是Serialize/Deserilize的簡稱,目的是用於序列化和反序列化。序列化的格式包括:分隔符(tab、逗號、CTRL-A)、Thrift 協議
反序列化(內存內):Java Integer/String/ArrayList/HashMap、Hadoop Writable類、用戶自定義類
其中,LazyObject只有在訪問到列的時候才進行反序列化。 BinarySortable保留了排序的二進制格式。
當存在以下情況時,可以考慮增加新的SerDe:
* 用戶的數據有特殊的序列化格式,當前的Hive不支持,而用戶又不想在將數據加載至Hive前轉換數據格式。
* 用戶有更有效的序列化磁盤數據的方法。
用戶如果想爲Text數據增加自定義Serde,可以參照contrib/src/java/org/apache/hadoop/hive/contrib/serde2/RegexSerDe.java中的例子。RegexSerDe利用用戶提供的正則表倒是來反序列化數據,例如:
-
CREATE TABLE apache_log(
-
host STRING,
-
identity STRING,
-
user STRING,
-
time STRING,
-
request STRING,
-
status STRING,
-
size STRING,
-
referer STRING,
-
agent STRING)
-
ROW FORMAT
-
SERDE 'org.apache.hadoop.hive.contrib.serde2.RegexSerDe'
-
WITH SERDEPROPERTIES
-
( "input.regex" = "([^ ]*) ([^ ]*) ([^ ]*) (-|\\[[^\\]]*\\])
-
([^ \"]*|\"[^\"]*\") (-|[0-9]*) (-|[0-9]*)(?: ([^ \"]*|\"[^\"]*\")
-
([^ \"]*|\"[^\"]*\"))?",
-
"output.format.string" = "%1$s %2$s %3$s %4$s %5$s %6$s %7$s %8$s %9$s";)
-
STORED AS TEXTFILE;
複製代碼
用戶如果想爲Binary數據增加自定義的SerDe,可以參考例子serde/src/java/org/apache/hadoop/hive/serde2/binarysortable,例如:
-
CREATE TABLE mythrift_table
-
ROW FORMAT SERDE
-
'org.apache.hadoop.hive.contrib.serde2.thrift.ThriftSerDe'
-
WITH SERDEPROPERTIES (
-
"serialization.class" = "com.facebook.serde.tprofiles.full",
-
"serialization.format" = "com.facebook.thrift.protocol.TBinaryProtocol";);
複製代碼
(3)Map/Reduce腳本(Transform)
用戶可以自定義Hive使用的Map/Reduce腳本,比如:
-
FROM (
-
SELECT TRANSFORM(user_id, page_url, unix_time)
-
USING 'page_url_to_id.py'
-
AS (user_id, page_id, unix_time)
-
FROM mylog
-
DISTRIBUTE BY user_id
-
SORT BY user_id, unix_time)
-
mylog2
-
SELECT TRANSFORM(user_id, page_id, unix_time)
-
USING 'my_python_session_cutter.py' AS (user_id, session_info);
複製代碼
Map/Reduce腳本通過stdin/stdout進行數據的讀寫,調試信息輸出到stderr。
(4)UDF(User-Defined-Function)
用戶可以自定義函數對數據進行處理,例如:
-
-
<P>[sql]</P>
-
<P>add jar build/ql/test/test-udfs.jar;
-
CREATE TEMPORARY FUNCTION testlength
-
AS 'org.apache.hadoop.hive.ql.udf.UDFTestLength';
-
-
SELECT testlength(src.value) FROM src;
-
-
DROP TEMPORARY FUNCTION testlength;</P>
複製代碼
UDFTestLength.java爲:
-
package org.apache.hadoop.hive.ql.udf;
-
-
public class UDFTestLength extends UDF {
-
public Integer evaluate(String s) {
-
if (s == null) {
-
return null;
-
}
-
return s.length();
-
}
-
}
複製代碼
UDF 具有以下特性:
* 用java寫UDF很容易。
* Hadoop的Writables/Text 具有較高性能。
* UDF可以被重載。
* Hive支持隱式類型轉換。
* UDF支持變長的參數。
* genericUDF 提供了較好的性能(避免了反射)。
(5)UDAF(User-Defined Aggregation Funcation)
例子:
-
-
<P>[sql]</P>
-
<P>SELECT page_url, count(1), count(DISTINCT user_id) FROM mylog;</P>
複製代碼
UDAFCount.java代碼如下:
-
public class UDAFCount extends UDAF {
-
public static class Evaluator implements UDAFEvaluator {
-
private int mCount;
-
-
public void init() {
-
mcount = 0;
-
}
-
-
public boolean iterate(Object o) {
-
if (o!=null)
-
mCount++;
-
-
return true;
-
}
-
-
public Integer terminatePartial() {
-
return mCount;
-
}
-
-
public boolean merge(Integer o) {
-
mCount += o;
-
return true;
-
}
-
-
public Integer terminate() {
-
return mCount;
-
}
-
}
複製代碼