Hive之自定义标准函数UDF

 

一、自定义简单标准函数(UDF)

1.定义:

   标准函数:指一行的一列或多列作为参数传入,返回单一值的函数。

   如:to_date(string timestamp),sqrt(double a),concat(string a,string b)等。

2.实现自定义concat:

   功能:用于将两个输入参数连接起来。

   两个重载函数:myconcat(string str1, string str2) 和 myconcat(int a, int b),如下Java代码:

   注1:UDF类在 hive-exec-2.3.4.jar 中;

   注2:用@Description() 可以给函数加使用说明;

   注3:继承UDF类,实现evaluate()方法(支持重载)。

package com.hive.udf;

import org.apache.hadoop.hive.ql.exec.Description;
import org.apache.hadoop.hive.ql.exec.UDF;
import org.apache.hadoop.io.Text;

/*
 * 自定义标准函数 ConcatUDF
 */
@Description(name = "myconcat",
	value = "_FUNC_(str1, str2)",
	extended = "Example:\n"
		+ "SELECT _FUNC_(string str1, string str2) FROM src;\n"
		+ "SELECT _FUNC_(int a, int b) FROM src;") 
public class ConcatUDF extends UDF{

	private Text text = new Text();
	
	public Text evaluate(Text str1, Text str2) {
		if (str1 == null || str2 == null) {
			text.set("unvalid");
			return text;
		}
		text.set(str1.toString() + "+" + str2.toString());
		return text;
	}
	
	public String evaluate(Integer a, Integer b) {
		if (a == null || b == null) {
			return "unvalid";
		}
		return a + "+" + b;
	}
	
}

 3.关于evaluate()方法的输入输出参数类型的说明:

 ---引用自《Hive编程指南》

UDF中evaluate()函数的参数和返回值类型只能是Hive可以序列化的数据类型。例如,如果用户处理的全是数值,那么UDF的输出参数类型可以是基本数据类型int、Integer封装的对象或者是一个IntWritable对象,也就是Hadoop对整型封装后的对象。用户不需要特别的关心将调用到哪个类型,因为当类型不一致的时候,Hive会自动将类型转换成匹配的类型。需要记住的是,null在Hive中对于任何数据类型都是合法的,但是对于Java基本数据类型,不能是对象,也不能是null。

4.打包Jar file,并运行测试 :

1.将com.hive.udf包右键导出为 JAR file,命名为:"myUDF.jar";
2.利用Windows的cmd或者PowerShell(推荐)将JAR文件上传到Linux服务器
  命令如下:(在JAR文件目录下执行)
  > scp myUDF.jar root@remoteIP:~/myJars/hive/
 (其中remoteIP为远程服务器IP)
3.启动hadoop,启动hive('hive>'下输入,仅支持全路径名)
  > add jar /root/myJars/hive/myUDF.jar
  <会提示成功加入 class path>
4.注册临时/永久函数
  > create temporary function myconcat as 'com.hive.udf.ConcatUDF';(临时,作用本次会话)
  > create function myconcat as 'com.hive.udf.ConcatUDF';(永久)
5.运行测试
  > select myconcat('a','b'), 
  >        myconcat(1,2);
  a+b    1+2
  <此即连接的结果>
  > select myconcat(null,'b'), 
  >        myconcat(null,2);
  unvalid    unvalid
  <此即参数为null的处理结果>

5.Hive函数的几个操作命令:

1.Hive函数相关命令:
  --显示所有包含'concat'子串的函数
  > show functions like '*concat*';
  --查看函数描述用法
  > desc function concat;
  --查看函数描述用法(详细)
  > desc function extended concat;
  --删除自定义函数
  > drop temporary function myconcat;

二、自定义复杂标准函数(UDF)

1.实现自定义nvl:

  功能:如果函数传入的参数是null,则返回默认值,否则返回传入值。函数需要两个参数,一个传入值,一个默认值。如果第一个参数为null,则返回第二个默认参数。

  注1:(回答了为什么要用GenericUDF实现 ?)此功能当然也能用简单UDF实现,但是当面对不同输入参数类型时,就需要重载很多个不同的evaluate()方法,非常复杂;由此,复杂UDF的实现,可以解决这个问题,GenericUDF会以编程的方式检查输入的数据类型,然后做出反馈。

  注2:需要继承GenericUDF类,实现initialize()、evaluate()、getDisplayString() 三个方法。

package com.hive.udf;

import org.apache.hadoop.hive.ql.exec.Description;
import org.apache.hadoop.hive.ql.exec.UDFArgumentException;
import org.apache.hadoop.hive.ql.exec.UDFArgumentLengthException;
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;

@Description(name="mynvl",
		value="_FUNC_(value,default_value) - Returns default value if value"
				+ " is null else returns value",
		extended="Examples:\n"
				+ "> SELECT _FUNC_(null,'bla') FROM src LIMIT 1;\n")
public class GenericNvlUDF extends GenericUDF{

	/*
	 * ObjectInspector:用来包装对各种输入参数类型的统一操作
	 */
	private ObjectInspector[] argumentOIs;
	/*
	 * ReturnObjectInspectorResolver:用来确定方法最终返回值的类型
	 * 		--update()是用来获取新参数的类型,并判断是否与之前参数类型一致(会自动拆装包)
	 */
	private GenericUDFUtils.ReturnObjectInspectorResolver returnOIResolver;
	
	/*
	 * initialize():输入参数类型检查
	 */
	@Override
	public ObjectInspector initialize(ObjectInspector[] arguments) throws UDFArgumentException {
		this.argumentOIs = arguments;
		if (arguments.length != 2) {
			throw new UDFArgumentLengthException("The operator 'NVL' accepts 2 arguments.");
		}
		//检查两个参数的数据类型是否匹配
		this.returnOIResolver = new GenericUDFUtils.ReturnObjectInspectorResolver(true);
		if (!(returnOIResolver.update(arguments[0]) && returnOIResolver.update(arguments[1]))) {
			throw new UDFArgumentTypeException(2,"The 1st and 2nd args of funciton NVL should have"
					+ "the same type, but they are different:\"" + arguments[0].getTypeName()
					+ "\" and \"" + arguments[1].getTypeName() + "\"");
		}
		return returnOIResolver.get();
	}

	/*
	 * evaluate():输入参数处理逻辑
	 */
	@Override
	public Object evaluate(DeferredObject[] arguments) throws HiveException {
		//如果第一个参数为null,则返回第二个默认参数
		//returnOIResolver.convertIfNecessary()对返回参数进一步转换类型
		Object retVal = returnOIResolver.convertIfNecessary(arguments[0].get(), argumentOIs[0]);
		if (retVal == null) {
			retVal = returnOIResolver.convertIfNecessary(arguments[1].get(), argumentOIs[1]);
		}
		return retVal;
	}

	/*
	 * getDisplayString():用于Hadoop task内部,使用到此函数时显示调试信息
	 */
	@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();
	}
	
}

2.打包Jar file,并运行 

1.将com.hive.udf包右键导出为 JAR file,命名为:"myUDF.jar";
2.利用Windows的cmd或者PowerShell(推荐)将JAR文件上传到Linux服务器
  命令如下:(在JAR文件目录下执行)
  > scp myUDF.jar root@remoteIP:~/myJars/hive/
 (其中remoteIP为远程服务器IP)
3.启动hadoop,启动hive('hive>'下输入,仅支持全路径名)
  > add jar /root/myJars/hive/myUDF.jar
  <会提示成功加入 class path>
4.注册临时/永久函数
  > create temporary function mynvl as 'com.hive.udf.GenericNvlUDF';(临时,作用本次会话)
  > create function myconcat as 'com.hive.udf.GenericNvlUDF';(永久)
5.运行测试
  > select mynvl('a','b'), 
  >        mynvl(1,2), 
  >        mynvl(array('a'),array('c','d')), 
  >        mynvl(map('a',1),map('b',2,'c',3)),
  >        mynvl(struct('a',1),struct('b',2));
  a   1    ["a"]    {"a":1}    {"col1":"a","col2":1}
  <即:第一个参数非null时返回第一个参数,支持不同类型>
  > select mynvl(null,'b'), 
  >        mynvl(1,'a'), 
  >        mynvl(null,array('c','d')), 
  >        mynvl(null,map('b',2,'c',3)),
  >        mynvl(null,struct('b',2));
  b   1    ["c","d"]    {"b":2,"c":3}    {"col1":"b","col2":2}
  <即:第一个参数为null时返回第二个默认参数>
  

 

三、参考文章

1.Hive UDF开发指南(简单UDF和复杂UDF实现)

2.《Hadoop海量数据处理:技术详解与项目实战》范东来 第6章 6.7.1 UDF

3.《Hive编程指南》第13章 13.7 UDF与GenericUDF

 

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值