Hive进阶之自定义函数学习

自定义函数

1 自定义函数的简介

1.1自定义函数来历

  1. hive的内置函数满足不了所有的业务需求‘
  2. hive提供很多的模板可以自定义功能,比如:自定义函数、serde、输入输出格式等。

1.2 自定义函数分类

  1. UDF:用户自定义函数,user defined function。一对一的输入输出。(最常用的)。
  2. UDTF:用户自定义表生成函数。user defined table-generate function,一对多的输入输出。lateral view explode
  3. UDAF:用户自定义聚合函数。user defined aggregate function 。多对一的输入输出count sum max。

2 自定义函数实现

2.1 UDF格式

创建maven项目,在pom.xml加入一下maven的依赖包

<dependency>
	<groupId>org.apache.hive</groupId> 
	<artifactId>hive-exec</artifactId> 
	<version>2.1.1</version> 
</dependency>

定义UDF函数要注意下面几点:

  1. 继承 org.apache.hadoop.hive.ql.exec.UDF
  2. 重写evaluate(),这个方法不是由接口定义的,因为它可接受的参数的个数,数据类型都是不确定。Hive会检查UDF,看能否找到和函数调用相匹配的evaluate()方法。
2.1.1 自定义函数第一个案例--------实现小写转大写
public class FirstUDF extends UDF { 
	public String evaluate(String str){ 
	//关于默认输出值是null,还是“”,这个要看需求具体定义,在这里先默认定义为 null, 
		String result = null; 
		//1、检查输入参数 
		if (!StringUtils.isEmpty(str)){ 
			result = str.toUpperCase(); 
		}
		return result; 
	}
	//调试自定义函数 
	public static void main(String[] args){ 
		System.out.println(new FirstUDF().evaluate("myedu")); 
	} 
}

2.2 函数加载方式

2.2.1第一种方法:命令加载(临时有效)

这种加载只对本session有效

# 将编写的udf的jar包上传到服务器上. 
# 并且将jar包添加到hive的class path中 
#实现方法
# 进入到hive客户端,执行下面命令 
hive> add jar /opt/jar/udf.jar
-- 创建一个临时函数名,要跟上面hive在同一个session里面: 
hive> create temporary function 函数名 as '类所在的路径即包名加类名’;
实例:
hive> create temporary function toUP as 'com.xxx.hive.FirstUDF'; 

-- 检查函数是否创建成功 
hive> show functions; 

-- 测试功能 
hive> select toUp('abcdef'); 

-- 删除函数 
hive> drop temporary function if exists toUP;
2.2.2 启动参数加载(也是在本session有效,临时函数)(临时生效)
# 1、将编写的udf的jar包上传到服务器上 
# 2、在hive的文件目录下创建配置文件 
[root@master hive]# vi ./hive-init 
# 加入下面脚本 
add jar /opt/jar/udf.jar; 
create temporary function toup as 'com.qf.hive.FirstUDF';
# 3、启动hive的时候带上初始化文件: 
[root@master hive]# hive -i ./hive-init 
hive> select toup('abcdef')
2.2.3 配置文件加载(永久生效)

通过配置文件方式这种只要用hive命令行启动都会加载函数

# 1、将编写的udf的jar包上传到服务器上
# 2、在hive的安装目录的bin目录下创建一个配置文件,文件名:.
 hiverc [root@master hive]# vi ./bin/.hiverc 
 add jar /hivedata/udf.jar; 
 create temporary function toup as 'com.qf.hive.FirstUDF'; 
 3、启动hive 
 [root@master hive]# hive

2.3 UDTF格式

UDTF是一对多的输入输出,实现UDTF需要完成下面步骤

  1. 继承org.apache.hadoop.hive.ql.udf.generic.GenericUDTF
  2. 重写 initlizer() 、 process() 、 close() 。

执行流程如下:

  • UDTF首先会调用initialize方法,此方法返回UDTF的返回行的信息(返回个数,类型)。
  • 初始化完成后,会调用process方法,真正的处理过程在process函数中,在process中每一次forward()调用产生一行;如果产生多列可以将多个列的值放在一个数组中,然后将数组传入到forward()函数。
  • 最后close()方法调用,对需要清理的方法进行清理。
2.3.1 需求
把"k1:v1;k2:v2;k3:v3"类似的的字符串解析成每一行多行,每一行按照key:value格式输出
2.3.2 代码

自定义函数如下:

/** 
* 定义一个UDTF的Hive自定义函数(一对多),默认要继承与GenericUDTF 
*/ 
public class ParseMapUDTF extends GenericUDTF { 

	//在initializez中初始化要输出字段的名称和类型 
	@Override
	public StructObjectInspector initialize(ObjectInspector[] argOIs) throws UDFArgumentException { 
		//定义要输出列的名字的List,并且添加要输出的列名 
		List<String> structFieldNames = new ArrayList<>(); 
		structFieldNames.add("key"); 
		structFieldNames.add("value"); 
		// 定义要输出列的类型的List,并且添加要输出列的类型 
		List<ObjectInspector> objectInspectorList = new ArrayList<>(); 
		objectInspectorList.add(PrimitiveObjectInspectorFactory.javaStringObjectI nspector); 
		
		objectInspectorList.add(PrimitiveObjectInspectorFactory.javaStringObjectI nspector);
		
		return ObjectInspectorFactory.getStandardStructObjectInspector(structFieldNames, objectInspectorList); 
	
}

	// process方法用来处理输入的每行数据,每行数据处理调用一次process,类似于 Mapper中的map方法 
	@Override 
	public void process(Object[] objects) throws HiveException { 
		// 得到第一个参数,转化为字符串,类似于->
		//name:zhang;age:30;address:shenzhen 
		String insputString = objects[0].toString(); 
		// 把上述例子字符串按照分号;切分为数组 
		String[] split = insputString.split(";"); 
		// s=name:zhang 
		for (String s : split) { 
		// 把每个切分后的key value分开 
		String[] kvArray = s.split(":"); 
		// 如果产生多列可以将多个列的值放在一个数组中,然后将该数组传入到 forward()函数。
		forward(kvArray); 
	} 
}

	@Override 
	public void close() throws HiveException {
	 
	 } 
 }
2.3.3 打包加载

对上述命令源文件打包为udtf.jar,拷贝到服务器的/opt/jar/目录

在Hive客户端把udf.jar加入到hive中,如下:

hive> add jar /opt/jar/udtf.jar;
2.3.4 创建临时函数

在Hive客户端创建函数:

# 创建一个临时函数parseMap 
hive> create temporary function parseMap as 'com.qf.hive.ParseMapUDTF'; 

# 查看函数是否加入 
hive> show functions ;
2.3.5 测试临时函数
hive> select parseMap("name:zhang;age:30;address:shenzhen");

结果如下:

#map key 
name zhang 
age 30 
address shenzhen

2.4 UDAF格式

用户自定义聚合函数。user defined aggregate function。多对一的输入输出 count summax。定义一个UDAF需要如下步骤:

  1. UDAF自定义函数必须是org.apache.hadoop.hive.ql.exec.UDAF的子类,并且包含一个或者多个嵌套的函数实现了org.apache.hadoop.hive.ql.exec.UDAFEvaluator的静态类。
  2. 函数类需要继承UDAF类,内部类Evaluator实现UDAFEvaluator接口。
  3. Evaluator需要实现 init、iterate、terminatePartial、merge、terminate这几个函数

这几个函数作用如下:
在这里插入图片描述

2.4.1 需求

计算一组整数的最大值

2.4.2 代码
/**
* 定义一个UDAF自定义函数类,默认要继承于UDAF类 
*/ 
//给当前函数添加描述信息,方便在desc function方法时查看
 @Description(name="maxInt",value = "Find Max Value" ,extended = "Extended:Find Max Value for all Col")
  public class MaxValueUDAF extends UDAF { 
	  //UDAF要求 并且包含一个或者多个嵌套的的实现了 
	  // org.apache.hadoop.hive.ql.exec.UDAFEvaluator的静态类。 
	  public static class MaxnumIntUDAFEvaluator implements UDAFEvaluator { 
	 		 //在静态类内部定义一个返回值,作为当前UDAF最后的唯一返回值,因为返回值要在 hive调用,所以必须要使用序列化类型 
		  	private IntWritable result;
			/**
			* 在初始化是把返回值设为null,避免和上次调用时混淆 
			*/ 
			@Override 
			public void init() { 
				result=null; 
			}
			//定义一个函数iterate用来处理遍历多行时,每行值传进来是调用的函数 
		    public boolean iterate(IntWritable value) { 
				// 把遍历每行的值value传入,和result比较,如果比result大,那么result就 设置为value,否则result不变 
				if (value == null) { 
					return true; 
				}
				//如果是第一行数据,那么直接给result赋值为第一行数据 
				if (result == null) { 
					result = new IntWritable(value.get()); 
				} else { 
				// 给result赋值result和value之间的最大值
				 	result.set(Math.max(result.get(),value.get()));
				}
				return true; 
		   }
		   /**
		   * 在map端进行并行执行后的结果 
		   * @return 
		   */ 
		   public IntWritable terminatePartial() { 
		   		return result; 
		   }
		   /**
		   * 接收terminatePartial的返回结果,进行数据merge操作,其返回类型为 boolean。
		   * @param other 
		   * @return 
		   */ 
		  	public boolean merge(IntWritable other) {
				return iterate( other ); 
			}
			/**
			* 将最终的结果返回为Hive 
			* @return 
			*/ 
			public IntWritable terminate() { 
				return result; 
			} 
	} 
}

注意:如果你要给自己写的函数加上desc function后的说明,可以在自定义函数类上面加上下面的注解:

@Description(name = "maxValue",value = "Find Max Value",extended ="Extended:Find Max Value for all Col")

hive> desc function maxInt;
hive> desc function extended maxInt;
2.4.3打包加载

对上述命令源文件打包为udaf.jar,拷贝到服务器的/opt/jar目录
在Hive客户端把udf.jar加入搭配hive中,如下:

hive> add jar /opt/jar/udaf.jar;
2.4.4创建临时函数

在Hive客户端创建函数

hive> create temporary function maxInt as 'com.qf.hive.MaxValueUDAF';
# 查看函数是否加入
hive> show functions ;
2.4.5测试临时函数
-- 使用前面的任意一个有int类型字段的表进行测试
hive> select maxInt(id) from dy_part1;
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值