【Hive】12-函式
使用者自定義函式( UDF )是一個允許使用者擴充套件 HiveQL 的強大的功能。正如我們將看到的,使用者使用 Java 進行編碼。一旦將使用者自定義函式加人到使用者會話中(互動式的或者通過指令碼執行的),它們就將和內建 的函式一樣使用,甚至可以提供聯機幫助。 Hive 具有多種型別的使用者自定義函式,每一種都會針對翰人資料執行特定“一類”的轉換過程。
在 ETL 處理中,一個處理過程可能包含多個處理步驟。 Hive 語言具有多種方式來將上一步驟的輸人通過管道傳遞給下一個步驟,然後在一個查詢中產生眾多輸出。使用者同樣可以針對一些特定的處理過程編寫自定義函式。如果沒有這個功能,那麼一個處理過程可能就需要包含一個 MapReduce 步驟或者需要將資料轉移到另一個系統中來實現這些改變。互聯絡統增加了複雜性,並且增加了配置錯誤或其他錯誤的發生機率。當資料量是 GB 甚至 TB 級別時,在不同系統中轉移資料,需要消耗大量的時間。與此相反, UDF 是在 Hive 查詢產生的相同的恤歡程序中執行的,因此它們可以高效地執行,而且其消除了和其他系統整合時所產生的複雜度。本章涵括建立和使用 UDF 的最佳實踐。
1、發現和描述函式
在編寫自定義 UDF 之前,我們先來熟悉下 Hive 中自帶的那些 UDF 。需要注意的是在 Hive 中通常使用“UDF“來表示任意的函式,包括使用者自定義的或者內建的。 SHOW FUNCTIONS 命令可以列舉出當前 Hive 會話中所載入的所有函式名稱,其中包括內裡的和使用者載入進來的函式,載入方式稍後會進行介紹:
hive>SHOW FUNCTIONS;
abs
acos
and
array
...
函式通常都有其自身的使用文件。使用 DESCRIBE FUNCTION 命令可以展示對應函式簡短的介紹:
hive > DBSCRIBE FUNCTION concat;
函式也可能包含更多的詳細文件,可以通過增加 EXTENDED 關鍵字進行檢視:
2、呼叫函式
如果想使用函式,只搖要在查詢中通過呼叫函式名,並傳人器要的引數即可。某些函式需要指定特定的引數個數和引數型別,而其他函式可以傳人一組引數,引數型別可以是多樣的。和關鍵字一樣,函式名也是保留的字串:
select concat(column1,column2) AS x from table;
3、標準函式
使用者自定義函式(英文縮寫為 UDF )這個術語在狹義的概念上還表示以一行資料中的一列或多列資料作為引數然後返回結果是一個值的函式。大多數函式都是屬於這類的。
我們使用的例子中包含了很多的數學函式。例如 round()和floor(),其可以將 DOUBLE 型別轉換為 BIGINT 型別.還有abs(),這個函式可以返回數值的絕對值。
需要注意的是,這些 UDF 同樣可以返回一個複雜的物件,例如 arry 、 map或者 struct 。
4、聚合函式
另一種函式是聚合函式。所有的聚合函式、使用者自定義函式和內建函式,都統稱為使用者自定義聚合函式( UDAF )。
聚合函式接受從零行到多行的零個到多個列,然後返回單一值。這樣的例子包括數學函式 sum(),其返回所有輸人求和後的值. avg()函式會計算所有輸入的值的平均值. min()和 max()函式,可以分別返回輸人值中的最小值和最大值:
聚合方法通常和 GROUP BY 語句組合使用。
5、表生成函式
Hive 所支援的第 3 類函式就是表生成函式。和其他函式類別一樣,所有的表生成函式,包括使用者自定義的和內建的,都統稱為使用者自定義表生成函式( UDTF )。
表生成函式接受零個或多個輔人,然後產生多列或多行輸出。例如, array 函式就是將一列輸人轉換成一個數組輸出的。下面的查詢語句中使用了 array 函式:
hive > SELECT array(1,2,3) FROM dual ;
[1 , 2, 3]
explode()函式以 array 型別資料作為輸人,然後對陣列中的資料進行迭代,返回多行結果,一行一個數組元素值。
hive > SELECT explode(array(1,2,3)) AS element FROM src ;
1
2
3
不過, Hive 只允許表生成函式以特定的方式使用。例如,一個顯著的限制就是,我們無法從表中產生其他的列。例如這個查詢可能是前面我們對於 employees 表進行的操作。我們可能需要列舉出每名僱員的下屬員工:
不過, Hive 提供了一個 LATERAL VIEW 功能來實現這種查詢:
需要注意的是,對於職位不是經理的僱員(即沒有下屬員工的人)來說是沒有輸出行的,例如 Bill King 和Toddd Jones 就不會有對應的輸出行。因此,輸出中將會產生零到多行新紀錄。通過 LATERAL VIEW 可以方便地將 explode 這個 UDTF 得到的行轉列的結果集合在一起提供服務。使用 LATERAL VlEW 需要指定檢視別名和生成的新列的別名,對於本例,其分別是 subview 和 sub。
6、編寫UDF
下面我們開始編寫自己的 UDF 。
import org.apache.hadoop.hive.ql.exec.UDF;
import org.apache.hadoop.io.Text;
public final class Lower extends UDF{
public Text evaluate(final Text s){
if(s==null){return null;}
return new Text(s.toString().toLowerCase());
}
}
編寫一個 UDF ,需要繼承 UDF 類並實現 evaluate()函式。在查詢執行過程中,查詢中對應的每個應用到這個函式的地方都會對這個類進行例項化。對於每行輸入都會呼叫到 evaluate()函式。而 evaluate()處理後的值會返回給 Hive 。同時使用者是可以過載 evaluate 方法的。 Hive會像 Java 的方法過載一樣,自動選擇匹配的方法。
提示:UDF 中evaluate() 函式的引數和返回位型別只能是 Hive 可以序列化的資料型別.例如,如果使用者處理的全是數值,那麼 UDF 的愉出引數型別可以是基本資料型別 int 、 Integer 封裝的物件或者是一個 IntWritable 物件,也就是 Hadoop 對整型封裝後的物件.使用者不雷要特別地關心將呼叫到哪個型別,因為當型別不一致的時候, Hive 會自動將型別轉換成匹配的型別.禽要記住的是, null 在 Hive 中對於任何資料型別都是合法的,但是對於 Java 基本資料型別,不能是物件,也不能是 null。如果想在 Hive 中使用 UDF .那麼而要將 Java 程式碼進行編譯,然後將編譯後的 UDF 二進位制類檔案打包成一個 JAR 檔案。然後,在 Hive 會話中,將這個 JAR 檔案加人到類路徑下,再通過 CREATE FUNCTION 語句定義好使用這個 Java 類的函式:
hive > ADD JAR /full/path/udf.jar;
hive > CREATE TEMPORARY FUNCTION zodac AS 'org.apache.hadoop.hive.contrib.udf.example.UDF';
需要注意的是, JAR 檔案路徑是不需要用引號括起來的,同時,到目前為止這個路徑需要是當前檔案系統的全路徑。 Hive 不僅僅將這個 JAR 檔案加人到 classPath 下,同時還將其加人到了分散式快取中,這樣整個叢集的機器都是可以獲得該 JAR 檔案的。現在這個判斷星座的 UDF 可以像其他的函式一樣使用了。需要注意下 CREATE FUNCTION 語句中的 TEMPoRARY 這個關鍵字。當前會話中宣告的函式只會在當前會話中有效。因此使用者需要在每個會話中都增加 JAR 然後建立函式。不過,如果使用者需要頻繁地使用同一個 JAR 檔案和函式的話,那麼可以將相關語句增加到$HOME/.hiverc檔案中去。
再次說明下, UDF 允許使用者在 Hive 語言中執行自定義的轉換過程。通過上面那個 UDF , Hive 現在可以通過使用者生日計算得到相應的星座名稱了,當然也可以做其他的聚合和轉換過程。當我們使用完自定義 UDF 後,我們可以通過如下命令刪除此函式:
hive > DROP TEMPORARY FUNCTION IF EXISTS zodiac;
像通常一樣, IF EXISTS 是可選的。如果增加此關鍵字,則即使函式不存在也不會報錯。