轉自:http://blog.csdn.net/zythy/article/details/18818559
當Hive提供的內置函數無法滿足你的業務處理需要時,此時就可以考慮使用用戶自定義函數(UDF:user-defined function)。
Hive目前只支持用java語言書寫自定義函數。如果需要採用其他語言,比如Python,可以考慮上一節提到的transform語法來實現。
Hive支持三種自定義函數,我們逐個講解。
UDF
這是普通的用戶自定義函數。接受單行輸入,併產生單行輸出。
編寫java代碼如下:
package com.oserp.hiveudf;
import org.apache.hadoop.hive.ql.exec.UDF;
import org.apache.hadoop.io.Text;
public classPassExam extendsUDF {
publicText evaluate(Integer score)
{
Text result = new Text();
if(score < 60)
result.set("Failed");
else
result.set("Pass");
return result;
}
}
然後,打包成.jar文件,比如hiveudf.jar。
執行以下語句:
add jar /home/user/hadoop_jar/hiveudf.jar;
create temporary function pass_scorecom.oserp.hiveudf.PassExam;
select stuNo,pass_score(score) from student;
輸出結果爲:
N0101 Pass
N0102 Failed
N0201 Pass
N0103 Pass
N0302 Pass
N0202 Pass
N0203 Pass
N0301 Failed
N0306 Pass
第一個語句註冊jar文件;第二個語句爲自定義函數取別名;第三個語句調用自定義函數。
Java代碼中,自定義函數的類繼承自UDF類,且提供了一個evaluate方法。這個方法接受一個整數值作爲參數,並返回字符串。結構十分明瞭。其中的evaluate方法並沒有作爲interface提供,因爲實際使用時,函數的參數個數及類型是多變的。
以上UDF名稱是不區分大小寫的,比如調用時寫成PASS_SCORE也是可以的(因爲它是hive中的別名,不是java類名)。
使用完成後,可調用以下語句刪除函數別名:
Drop temporary function pass_score;
UDAF
用戶定義聚集函數(User-defined aggregate function)。接受多行輸入,併產生單行輸出。比如MAX,COUNT函數。
編寫以下Java代碼:
packagecom.oserp.hiveudf;
importorg.apache.hadoop.hive.ql.exec.UDAF;
importorg.apache.hadoop.hive.ql.exec.UDAFEvaluator;
importorg.apache.hadoop.hive.serde2.io.DoubleWritable;
importorg.apache.hadoop.io.IntWritable;
publicclass HiveAvgextends UDAF {
public staticclass AvgEvaluate implements UDAFEvaluator
{
public staticclass PartialResult
{
public intcount;
public doubletotal;
public PartialResult()
{
count = 0;
total = 0;
}
}
private PartialResultpartialResult;
@Override
public voidinit() {
partialResult = new PartialResult();
}
public booleaniterate(IntWritable value)
{
// 此處一定要判斷partialResult是否爲空,否則會報錯
// 原因就是init函數只會被調用一遍,不會爲每個部分聚集操作去做初始化
//此處如果不加判斷就會出錯
if (partialResult==null)
{
partialResult =new PartialResult();
}
if (value !=null)
{
partialResult.total =partialResult.total +value.get();
partialResult.count=partialResult.count + 1;
}
return true;
}
public PartialResult terminatePartial()
{
returnpartialResult;
}
public booleanmerge(PartialResult other)
{
partialResult.total=partialResult.total + other.total;
partialResult.count=partialResult.count + other.count;
return true;
}
public DoubleWritable terminate()
{
return newDoubleWritable(partialResult.total /partialResult.count);
}
}
}
然後打包成jar文件,比如hiveudf.jar。
執行以下語句:
add jar/home/user/hadoop_jar/hiveudf.jar;
create temporary function avg_udf as'com.oserp.hiveudf.HiveAvg';
select classNo, avg_udf(score) from studentgroup by classNo;
輸出結果如下:
C01 68.66666666666667
C02 80.66666666666667
C03 73.33333333333333
參照以上圖示(來自Hadoop權威教程)我們來看看各個函數:
l Init在類似於構造函數,用於UDF的初始化。
注意上圖中紅色框中的init函數。在實際運行中,無論hive將記錄集劃分了多少個部分去做(比如上圖中的file1和file2兩個部分),init函數僅被調用一次。所以上圖中的示例是有歧義的。這也是爲什麼上面的代碼中加了特別的註釋來說明。或者換一句話說,init函數中不應該用於初始化部分聚集值相關的邏輯,而應該處理全局的一些數據邏輯。
l Iterate函數用於聚合。當每一個新的值被聚合時,此函數被調用。
l TerminatePartial函數在部分聚合完成後被調用。當hive希望得到部分記錄的聚合結果時,此函數被調用。
l Merge函數用於合併先前得到的部分聚合結果(也可以理解爲分塊記錄的聚合結果)。
l Terminate返回最終的聚合結果。
我們可以看出merge的輸入參數類型和terminatePartial函數的返回值類型必須是一致的。
UDTF
用戶定義表生成函數(User-defined table-generating function)。接受單行輸入,併產生多行輸出(即一個表)。不是特別常用,此處不詳述。