UDF概述
UDF全称:User-Defined Functions,即用户自定义函数,在Hive SQL编译成MapReduce任务时,执行java方法,类似于像MapReduce执行过程中加入一个插件,方便扩展。
UDF种类
自定义UDF步骤
1.编写UDF函数,
- UDF需要继承
org.apache.hadoop.hive.ql.exec.UDF
- UDTF继承
org.apache.hadoop.hive.ql.udf.generic.GenericUDTF
- UDAF使用比较少,这里先不讲解
2.将写好的类打包为jar,如HiveUDF-1.0.jar,并且上传到Hive机器或者HDFS目录
3.入到Hive shell环境中,输入命令注册该jar文件;
1
| add jar /home/hadoop/HiveUDF-1.0.jar
|
或者
把HiveUDF-1.0.jar上传到hdfs,
1
| hadoop fs -put HiveUDF-1.0.jar /home/hadoop/HiveUDF-1.0.jar
|
再输入命令
1
| add jar hdfs://hadoop01:9000/home/hadoop/HiveUDF-1.0.jar
|
4.为UDF类起一个别名,
1
| create temporary function myudf as 'cn.psvmc.udf.MyUDF'
|
注意,这里UDF只是为这个Hive会话临时定义的;
5.在select中使用myudf();
注册UDF
临时注册
添加jar到hive的classpath
1
| add jar HiveUDF-1.0.jar;
|
注册临时函数
1
| create temporary function myudf AS 'cn.psvmc.udf.MyUDF';
|
删除临时注册函数
1
| drop temporary function myudf;
|
永久注册
1
| create function myudf as 'cn.psvmc.udf.MyUDF' using jar 'hdfs://hadoop01:9000/home/hadoop/HiveUDF-1.0.jar';
|
注意:
永久注册需要将jar包上传到hdfs,否则在集群中运行的时候,会出现找不到jar包的情况!
查看注册的函数
实例UDF
现在我们实现一个字符串转大写的UDF。
Hive建表测试及数据
1 2 3 4 5 6 7
| create table if not exists t_user ( id int, name string ) clustered by (id) into 2 buckets row format delimited fields terminated by '|' stored as orc TBLPROPERTIES('transactional'='true');
|
复制
向Hive表中插入数据:
1 2
| insert into t_user values(1,'Ba|qz'); insert into t_user values(1,'xa');
|
项目中添加依赖
1 2 3 4 5
| <dependency> <groupId>org.apache.hive</groupId> <artifactId>hive-exec</artifactId> <version>2.1.1</version> </dependency>
|
添加evaluate有两个注意事项:
1)evaluate方法遵循重载的原则,参数是用户自定义的,调用那个方法调用是在使用函数时候的参数决定。
2)evaluate方法必须有返回值,返回类型以及方法参数可以是Java数据或相应的Writable类。
如
1 2 3 4 5 6 7 8 9 10 11 12
| package cn.psvmc.udf;
import org.apache.hadoop.hive.ql.exec.UDF;
public class MyUDF extends UDF { public String evaluate(String s) { if (s == null) { return ""; } return s.toUpperCase(); } }
|
上传到Linux目录,然后用add jar来添加路径
1
| add jar /home/hadoop/hivetest/HiveUDF-1.0.jar
|
创建临时函数:
1
| create temporary function myudf as "com.master.HiveUDF.MyUDF";
|
UDF使用
1
| select myudf(name) from t_user;
|
重载示例
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| package cn.psvmc.udf;
import org.apache.hadoop.hive.ql.exec.UDF; import org.apache.hadoop.io.IntWritable; import org.apache.hadoop.io.Text;
public class TestHiveSimpleUDF extends UDF { public IntWritable evaluate(IntWritable i) { return new IntWritable(i.get()); }
public Text evaluate(Text text) { return new Text(text.toString()); } }
|
实例UDTF
initialize方法制定了返回的列名及数据类型(forward写入数据的类型是一个数组,对应着initialize定义的列名),可以返回多个,在List里面对应即可。
函数列名调用的时侯通过:myudtf(c1,c2) t1 as co1,col2来使用列名。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41
| package cn.psvmc.udf;
import java.util.ArrayList;
import java.util.List;
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;
public class MyUDTF extends GenericUDTF {
@Override public StructObjectInspector initialize(ObjectInspector[] argOIs) throws UDFArgumentException { List<String> fieldNameList = new ArrayList<>(); List<ObjectInspector> fieldTypeList = new ArrayList<>(); fieldNameList.add("col"); fieldTypeList.add(PrimitiveObjectInspectorFactory.javaStringObjectInspector); return ObjectInspectorFactory.getStandardStructObjectInspector(fieldNameList, fieldTypeList); }
@Override public void process(Object[] args) throws HiveException { String col = args[0].toString(); String[] cols = col.split("\\|"); for (String c : cols) { String[] results = new String[1]; results[0] = c; forward(results); } }
@Override public void close() throws HiveException {
} }
|
UDTF使用
1
| select myudtf(name) from t_user;
|
和前面的数据结合,这时候,需要用lateral view来操作,语句如下
1
| select t1.id,t2.col from t_user t1 lateral view myudtf(name) t2 as col
|