当Hive提供的内置函数没法知足你的业务处理须要时,此时就能够考虑使用用户自定义函数(UDF:user-defined function)。java
Hive目前只支持用java语言书写自定义函数。若是须要采用其余语言,好比Python,能够考虑上一节提到的transform语法来实现。apache
Hive支持三种自定义函数,咱们逐个讲解。ide
这是普通的用户自定义函数。接受单行输入,并产生单行输出。函数
编写java代码以下:oop
package com.oserp.hiveudf;lua
import org.apache.hadoop.hive.ql.exec.UDF;spa
import org.apache.hadoop.io.Text;orm
public classPassExam extendsUDF {blog
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;
用户定义汇集函数(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函数的返回值类型必须是一致的。
用户定义表生成函数(User-defined table-generating function)。接受单行输入,并产生多行输出(即一个表)。不是特别经常使用,此处不详述。