hive UDF 编程
UDF的定义
- UDF(User-Defined Functions)即是用户定义的hive函数。hive自带的函数并不能完全满足业务需求,这时就需要我们自定义函数了
UDF的分类
- UDF:one to one,进来一个出去一个,row mapping。是row级别操作,如:upper、substr函数
- UDAF:many to one,进来多个出去一个,row mapping。是row级别操作,如sum/min。
- UDTF:one to many ,进来一个出去多个。如alteral view与explode
自定义UDF
引入maven依赖
<dependency> <groupId>org.apache.hive</groupId> <artifactId>hive-exec</artifactId> <version>2.3.0</version> </dependency>
实现抽象类GenericUDF
该类的全路径为:org.apache.hadoop.hive.ql.udf.generic.GenericUDF
1)抽象类GenericUDF解释
GenericUDF类如下:
public abstract class GenericUDF implements Closeable { ... /* 实例化后initialize方法只会调用一次 - 参数arguments即udf接收的参数列表对应的objectinspector - 返回的ObjectInspector对象就是udf返回值的对应的objectinspector initialize方法中往往做的工作是检查一下arguments是否和你udf需要的参数个数以及类型是否匹配。 */ public abstract ObjectInspector initialize(ObjectInspector[] arguments) throws UDFArgumentException; ... // 真正的udf逻辑在这里实现 // - 参数arguments即udf函数输入数据,这个数组的长度和initialize的参数长度一样 // public abstract Object evaluate(DeferredObject[] arguments) throws HiveException; }
关于ObjectInspector,HIVE在传递数据时会包含数据本身以及对应的ObjectInspector,ObjectInspector中包含数据类型信息,通过oi去解析获得数据。
2) 实例
public class DateFeaker extends GenericUDF{ private static final SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd"); private transient ObjectInspectorConverters.Converter[] converters; @Override public ObjectInspector initialize(ObjectInspector[] arguments) throws UDFArgumentException { if (arguments.length != 2) { throw new UDFArgumentLengthException( "The function date_util(startdate,enddate) takes exactly 2 arguments."); } converters = new ObjectInspectorConverters.Converter[arguments.length]; for (int i = 0; i < arguments.length; i++) { converters[i] = ObjectInspectorConverters.getConverter(arguments[i], PrimitiveObjectInspectorFactory.writableStringObjectInspector); } return ObjectInspectorFactory .getStandardListObjectInspector(PrimitiveObjectInspectorFactory .writableStringObjectInspector); } @Override public Object evaluate(DeferredObject[] arguments) throws HiveException { if (arguments.length != 2) { throw new UDFArgumentLengthException( "The function date_util(startdate,enddate) takes exactly 2 arguments."); } ArrayList<Text> temp = new ArrayList<Text>(); if (arguments[0].get() == null || arguments[1].get() == null) { return null; } System.out.println(converters[0].getClass().getName()); System.out.println(arguments[0].getClass().getName()); Text startDate = (Text) converters[0].convert(arguments[0].get()); Text endDate = (Text) converters[1].convert(arguments[1].get()); Date start; try { start = sdf.parse(startDate.toString()); } catch (ParseException e) { e.printStackTrace(); throw new UDFArgumentException( "The First Argument does not match the parttern yyyy-MM-dd "+arguments[0].get()); } Date end; try { end = sdf.parse(endDate.toString()); } catch (ParseException e) { e.printStackTrace(); throw new UDFArgumentException( "The Second Argument does not match the parttern yyyy-MM-dd "+arguments[1].get()); } Calendar c = Calendar.getInstance(); while(start.getTime()<=end.getTime()){ temp.add(new Text(sdf.format(start))); c.setTime(start); c.add(Calendar.DATE, 1); start = c.getTime(); } return temp; } @Override public String getDisplayString(String[] children) { assert (children.length == 2); return getStandardDisplayString("date_util", children); }
3)部署UDF函数
上传jar包
[hadoop@hadoop001 lib]$hadoop fs -put g6-hadoop-1.0.jar hdfs://chd:8020/user
- 注意:如果jar包是上传到$HIVE_HOME/lib/目录以下,就不需要执行add命令了
添加jar包到hive
- 语法:add jar +jar包所在的目录/jar包名字
hive> add jar /home/hadoop/data/hive/g6-hadoop-1.0.jar;
在hive中创建UDF函数
1)创建临时函数 -----只对当前黑窗口有效
CREATE TEMPORARY FUNCTION function_name AS class_name;
function_name函数名
*******class_name 类路径,包名+类名********* 这里就是你写的UDF函数的第一行的package后边的东西然后在加个点加个类的名字
删除临时函数 :
- 语法:DROP TEMPORARY FUNCTION [IF EXISTS] function_name;
CREATE TEMPORARY FUNCTION function_name AS class_name USING JAR path; function_name函数名 class_name 类路径, 包名+类名 path jar包hdfs路径
实例
CREATE FUNCTION HelloUDF AS 'org.apache.hadoop.hive.ql.udf.HelloUDF' USING JAR 'hdfs://hadoop001:9000/lib/g6-hadoop-1.0.jar'; #测试 hive> select HelloUDF("17") ; OK hello:17
4)推荐比较全的实例
git地址:https://github.com/tchqiq/HiveUDF/tree/master/src/main/java/cn/com/diditaxi/hive/cf
我不生产知识 我只是知识的搬运工