Hive之——GenericUDF

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/l1028386804/article/details/88531631

转载请注明出处: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文件中。

 

猜你喜欢

转载自blog.csdn.net/l1028386804/article/details/88531631
0条评论
添加一条新回复