(6)Hive 高階程式設計——深入淺出學Hive
阿新 • • 發佈:2018-12-22
第一部分:產生背景 產生背景 •為了滿足客戶個性化的需求,Hive被設計成一個很開放的系統,很多內容都支援使用者定製,包括: •檔案格式:Text File,Sequence File •記憶體中的資料格式: Java Integer/String, Hadoop IntWritable/Text •使用者提供的 map/reduce 指令碼:不管什麼語言,利用 stdin/stdout 傳輸資料 •使用者自定義函式 自定義函式 •雖然Hive提供了很多函式,但是有些還是難以滿足我們的需求。因此Hive提供了自定義函式開發 •自定義函式包括三種UDF、UADF、UDTF •UDF(User-Defined-Function) •UDAF(User- Defined Aggregation Funcation) •UDTF(User-Defined Table-Generating Functions) 用來解決 輸入一行輸出多行(On-to-many maping) 的需求。 HIVE中使用定義的函式的三種方式 •在HIVE會話中add 自定義函式的jar檔案,然後建立function,繼而使用函式 •在進入HIVE會話之前先自動執行建立function,不用使用者手工建立 •把自定義的函式寫到系統函式中,使之成為HIVE的一個預設函式,這樣就不需要create temporary function 第二部分:UDF UDF用法 •UDF(User-Defined-Function) •UDF函式可以直接應用於select語句,對查詢結構做格式化處理後,再輸出內容 •編寫UDF函式的時候需要注意一下幾點 •自定義UDF需要繼承org.apache.hadoop.hive.ql.UDF •需要實現evaluate函式 •evaluate函式支援過載 •UDF只能實現一進一出的操作,如果需要實現多進一出,則需要實現UDAF UDF用法程式碼示例 import org.apache.Hadoop.hive.ql.exec.UDF public class Helloword extends UDF{ public String evaluate(){ return "hello world!"; } public String evaluate(String str){ return "hello world: " + str; } } 開發步驟 •開發程式碼 •把程式打包放到目標機器上去 •進入hive客戶端 •新增jar包:hive>add jar /run/jar/udf_test.jar; •建立臨時函式:hive>CREATE TEMPORARY FUNCTION my_add AS 'com.hive.udf.Add ‘ •查詢HQL語句: •SELECT my_add (8, 9) FROM scores; •SELECT my_add (scores.math, scores.art) FROM scores; •銷燬臨時函式:hive> DROP TEMPORARY FUNCTION my_add ; •細節 •在使用UDF的時候,會自動進行型別轉換,例如: SELECT my_add (8,9.1) FROM scores; •結果是17.1,UDF將型別為Int的引數轉化成double。型別的飲食轉換是通過UDFResolver來進行控制的 第三部分:UDAF UDAF •Hive查詢資料時,有些聚類函式在HQL沒有自帶,需要使用者自定義實現 •使用者自定義聚合函式: Sum, Average…… n – 1 •UDAF(User- Defined Aggregation Funcation) 用法 •一下兩個包是必須的import org.apache.hadoop.hive.ql.exec.UDAF和 org.apache.hadoop.hive.ql.exec.UDAFEvaluator 開發步驟 •函式類需要繼承UDAF類,內部類Evaluator實UDAFEvaluator介面 •Evaluator需要實現 init、iterate、terminatePartial、merge、terminate這幾個函式 a)init函式實現介面UDAFEvaluator的init函式。 b)iterate接收傳入的引數,並進行內部的輪轉。其返回型別為boolean。 c)terminatePartial無引數,其為iterate函式輪轉結束後,返回輪轉資料,terminatePartial類似於hadoop的Combiner。 d)merge接收terminatePartial的返回結果,進行資料merge操作,其返回型別為boolean。 e)terminate返回最終的聚集函式結果。 執行步驟 •執行求平均數函式的步驟 a)將java檔案編譯成Avg_test.jar。 b)進入hive客戶端新增jar包: hive>add jar /run/jar/Avg_test.jar。 c)建立臨時函式: hive>create temporary function avg_test 'hive.udaf.Avg'; d)查詢語句: hive>select avg_test(scores.math) from scores; e)銷燬臨時函式: hive>drop temporary function avg_test; UDAF程式碼示例 public class MyAvg extends UDAF { public static class AvgEvaluator implements UDAFEvaluator { } public void init() {} public boolean iterate(Double o) {} public AvgState terminatePartial() {} public boolean terminatePartial(Double o) { } public Double terminate() {} } 第四部分:UDTF UDTF •UDTF(User-Defined Table-Generating Functions) 用來解決 輸入一行輸出多行(On-to-many maping) 的需求。 開發步驟 •UDTF步驟: •必須繼承org.apache.Hadoop.hive.ql.udf.generic.GenericUDTF •實現initialize, process, close三個方法 •UDTF首先會 •呼叫initialize方法,此方法返回UDTF的返回行的資訊(返回個數,型別) 初始化完成後,會呼叫process方法,對傳入的引數進行處理,可以通過forword()方法把結果返回 •最後close()方法呼叫,對需要清理的方法進行清理 使用方法 •UDTF有兩種使用方法,一種直接放到select後面,一種和lateral view一起使用 •直接select中使用:select explode_map(properties) as (col1,col2) from src; •不可以新增其他欄位使用:select a, explode_map(properties) as (col1,col2) from src •不可以巢狀呼叫:select explode_map(explode_map(properties)) from src •不可以和group by/cluster by/distribute by/sort by一起使用:select explode_map(properties) as (col1,col2) from src group by col1, col2 •和lateral view一起使用:select src.id, mytable.col1, mytable.col2 from src lateral view explode_map(properties) mytable as col1, col2; 此方法更為方便日常使用。執行過程相當於單獨執行了兩次抽取,然後union到一個表裡。 lateral view • Lateral View語法 •lateralView: LATERAL VIEW udtf(expression) tableAlias AS columnAlias (',' columnAlias)* fromClause: FROM baseTable (lateralView)* •Lateral View用於UDTF(user-defined table generating functions)中將行轉成列,例如explode(). •目前Lateral View不支援有上而下的優化。如果使用Where子句,查詢可能將不被編譯。解決方法見: 此時,在查詢之前執行set hive.optimize.ppd=false; • 例子 •pageAds。它有兩個列 string pageid Array<int> adid_list " front_page" [1, 2, 3] "contact_page " [ 3, 4, 5] •SELECT pageid, adid FROM pageAds LATERAL VIEW explode(adid_list) adTable AS adid; •將輸出如下結果 string pageid int adid "front_page" 1 ……. “contact_page" 3 程式碼示例 public class MyUDTF extends GenericUDTF{ public StructObjectInspector initialize(ObjectInspector[] args) {} public void process(Object[] args) throws HiveException { } } 實現:切分 ” key:value;key:value;” 這種字串, 返回結果為 key, value 兩個欄位