hive UDF 编程

UDF的定义

  • UDF(User-Defined Functions)即是用户定义的hive函数。hive自带的函数并不能完全满足业务需求,这时就需要我们自定义函数了

UDF的分类

  1. UDF:one to one,进来一个出去一个,row mapping。是row级别操作,如:upper、substr函数
  2. UDAF:many to one,进来多个出去一个,row mapping。是row级别操作,如sum/min。
  3. 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

 

posted @ 2020-09-02 15:14  吊车尾88  阅读(512)  评论(0编辑  收藏  举报