概述:
UDF函数其实就是一个简单的函数,执行过程就是在Hive转换成MapReduce程序后,执行java方法,类似于像MapReduce执行过程中加入一个插件,方便扩展。UDF只能实现一进一出的操作,如果需要实现多进一出,则需要实现UDAF。
Hive可以允许用户编写自己定义的函数UDF,来在查询中使用。
UDF类型:
Hive中有三种UDF:
UDF:操作单个数据行,产生单个数据行;
UDAF:操作多个数据行,产生一个数据行;
UDTF:操作一个数据行,产生多个数据行一个表作为输出;
如何构建UDF(原理):
用户构建UDF使用过程如下:
- 继承UDF或者UDAF或者UDTF,实现特定的方法;
- 将写好的类打包成jar包,将jar包上传到Linux中;
- 在Linux中将jar上传到Hadoop中的hdfs上;
- 然后在hive黑窗口界面中输入以下命令:create function myfunc(自定义方法名) as “com.kb06.UdfFunction”(类的全包路径) using jar “hdfs://192.168.56.101:9000/func/myfun.jar”(jar包在hdfs上的位置);
- 最后在select中调用该函数就可以了, select myfunc();
UDF代码实现:
pom.xml依赖
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.11</version>
<scope>test</scope>
</dependency>
<!-- https://mvnrepository.com/artifact/org.apache.hadoop/hadoop-common -->
<dependency>
<groupId>org.apache.hadoop</groupId>
<artifactId>hadoop-common</artifactId>
<version>2.6.0</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.apache.hive/hive-exec -->
<dependency>
<groupId>org.apache.hive</groupId>
<artifactId>hive-exec</artifactId>
<version>1.1.0</version>
</dependency>
</dependencies>
如果想改打包之后的包名,可以在pom文件中的build标签内加一个标签,操作如下图:
UDF代码:
我的业务是想统计集合里面male和female的个数
package com.kb06;
import org.apache.hadoop.hive.ql.exec.UDF;
import org.apache.hadoop.io.Text;
import java.util.ArrayList;
public class MyFunc extends UDF {
public Text evaluate(ArrayList<Text> txt){
int male = 0;
int female = 0;
for (Text text : txt) {
String sex = text.toString();
if(sex.equalsIgnoreCase("male")){
male++;
}else {
female++;
}
}
return new Text("male"+male+",female"+female);
}
}
打成jar包:
注册UDF:
//先将jar包上传到Linux,然后上传到hdfs上
hdfs dfs -put /opt/myfun.jar /func
//注册UDF
create function myfunc as "com.kb06.UdfFunc" using jar "hdfs://192.168.56.101:9000"/func/myfun.jar
测试:
select myfunc(collect_list(gender)) from students;
UDTF代码实现:
编写UDTF需要继承GenericUDTF类,然后重写initialize方法和process方法和close方法
initialize方法主要是初始化返回的列和返回的列类型
process方法对输入的每一行进行操作,他通过调用forward()返回一行或者多行数据
close方法在process方法结束后调用,用于进行一些其他的操作,只执行一次
通过UDTF将爱好拆分为两列
import org.apache.hadoop.hive.ql.exec.UDFArgumentException;
import org.apache.hadoop.hive.ql.metadata.HiveException;
import org.apache.hadoop.hive.ql.udf.generic.GenericUDTF;
import org.apache.hadoop.hive.serde2.objectinspector.ObjectInspector;
import org.apache.hadoop.hive.serde2.objectinspector.ObjectInspectorFactory;
import org.apache.hadoop.hive.serde2.objectinspector.StructObjectInspector;
import org.apache.hadoop.hive.serde2.objectinspector.primitive.PrimitiveObjectInspectorFactory;
import java.util.ArrayList;
public class SimpleUDTF extends GenericUDTF {
@Override
public StructObjectInspector initialize(StructObjectInspector argOIs) throws UDFArgumentException {
ArrayList<String> colNames = new ArrayList<String>();
colNames.add("hobby1");
colNames.add("hobby2");
ArrayList<ObjectInspector> fieldIOs = new ArrayList<ObjectInspector>();
fieldIOs.add(PrimitiveObjectInspectorFactory.javaStringObjectInspector);
fieldIOs.add(PrimitiveObjectInspectorFactory.javaStringObjectInspector);
return ObjectInspectorFactory.getStandardStructObjectInspector(colNames,fieldIOs);
}
public void process(Object[] objects) throws HiveException {
forward(objects[0].toString().split(","));
}
public void close() throws HiveException {
}
}
打包测试:
add jar test_udtf.jar
create temporary function udf as 'com.mwf.demo.SimpleUDTF'
select udtf(hobby) from user;
UDAF代码实现:
可以参考该网址:UDAF精讲