转载请注明出处:https://blog.csdn.net/l1028386804/article/details/88531631
通过继承GenericUDF类来编写一个用户自定义函数,我们称之为nvl(),这个函数传入的值如果是null,那么就返回一个默认值。
函数nvl()要求有2个参数。如果第1个参数是非null值,那么就返回这个值;如果第1个参数是null,那么就返回地2个参数的值。GenericUDF框架正适合处理这类问题
我们先来创建这个类GenericUDFNvl
package com.lyz.hadoop.hive.generic.udf;
import org.apache.hadoop.hive.ql.exec.Description;
import org.apache.hadoop.hive.ql.exec.UDFArgumentException;
import org.apache.hadoop.hive.ql.exec.UDFArgumentTypeException;
import org.apache.hadoop.hive.ql.metadata.HiveException;
import org.apache.hadoop.hive.ql.udf.generic.GenericUDF;
import org.apache.hadoop.hive.ql.udf.generic.GenericUDFUtils;
import org.apache.hadoop.hive.serde2.objectinspector.ObjectInspector;
/**
* 利用GenericUDF实现传入的值如果是null,那么就会返回一个默认值的函数。
* @author liuyazhuang
*
*/
@Description(name="nvl",
value="_FUNC_(value, default_value) - Returns default value if value is null else returns value",
extended = "Example:\n"
+ " > SELECT _FUNC_(null, 'bla') FROM src limit 1; \n")
public class GenericUDFNvl extends GenericUDF {
private GenericUDFUtils.ReturnObjectInspectorResolver returnOIResolver;
private ObjectInspector[] argumentOIs;
@Override
public ObjectInspector initialize(ObjectInspector[] arguments) throws UDFArgumentException {
argumentOIs = arguments;
if(arguments.length != 2) {
throw new UDFArgumentException("The operator 'NVL' accepts 2 arguments.");
}
returnOIResolver = new GenericUDFUtils.ReturnObjectInspectorResolver(true);
if(!(returnOIResolver.update(arguments[0]) && returnOIResolver.update(arguments[1]))) {
throw new UDFArgumentTypeException(2, "The 1st and 2nd args of function NLV should have the same type, "
+ "but they are different: \""+arguments[0].getTypeName()+"\" and \"" + arguments[1].getTypeName() + "\"");
}
return returnOIResolver.get();
}
@Override
public Object evaluate(DeferredObject[] arguments) throws HiveException {
Object retVal = returnOIResolver.convertIfNecessary(arguments[0].get(), argumentOIs[0]);
if(retVal == null) {
retVal = returnOIResolver.convertIfNecessary(arguments[1].get(), argumentOIs[1]);
}
return retVal;
}
@Override
public String getDisplayString(String[] children) {
StringBuilder sb = new StringBuilder();
sb.append("if ");
sb.append(children[0]);
sb.append(" is null ");
sb.append("returns ");
sb.append(children[1]);
return sb.toString();
}
}
其中,initialize()方法会被输入的每隔参数调用,并最终传入到一个ObjectInspector对象中。这个方法的目标是确定参数的返回类型。乳沟传入的方法类型是不合法的,抛出异常、returnOIResolver是一个内置的类,通过获取非null值的变量的类型并使用这个数据类型来确定返回值类型。
方法evaluate的输入是一个DeferredObject对象数组,而initialize方法中创建的returnOIResolver对象用于从DeferredObjects对象中获取到控制。在这种情况下,这个函数会返回第1个非null值:
最后一个要实现的方法是getDisplayString(),其用于Hadoop task内部,在使用到这个函数时来展示调试信息。
接下来我们将这个类导出为Jar包,generic.jar,并将其上传到服务器的/usr/local/src目录。
然后在Hive命令行执行:
hive> add jar /usr/local/src/generic.jar;
hive> create temporary function nvl as 'com.lyz.hadoop.hive.generic.udf.GenericUDFNvl';
hive> describe function nvl;
OK
nvl(value, default_value) - Returns default value if value is null else returns value
Time taken: 0.017 seconds, Fetched: 1 row(s)
hive> describe function extended nvl;
OK
nvl(value, default_value) - Returns default value if value is null else returns value
Example:
> SELECT nvl(null, 'bla') FROM src limit 1;
Function class:com.lyz.hadoop.hive.generic.udf.GenericUDFNvl
Function type:TEMPORARY
Time taken: 0.022 seconds, Fetched: 6 row(s)
下面是展示这个函数的用法实例:
hive> select nvl(1, 2) as col1, nvl(NULL, 5) as col2, nvl(NULL, "STUFF") as col3 from a limit 1;
OK
1 5 STUFF
Time taken: 0.329 seconds, Fetched: 1 row(s)
注意:create function语句中的temporary关键字。当前会话中声明的函数只会在当前会话有效。因此用户需要在每个会话中都增加Jar然后创建函数。不过,如果用户频繁的使用同一个Jar文件和函数的话,可以将相关的语句增加到$HOME/.hiverc文件中。