Hive中的自定义hive函数

        Hive中的自带函数有时候无法满足我们的需求,因此我们需要自定义hive函数把一些复杂的HQL语句封装起来。我们一般只自定义UDF和UDTF函数,不去自定义UDAF函数是因为自带的UDAF函数以及可以解决大部分问题。

自定义函数需要通过编程的方式来进行,编程步骤:

1继承 org.apache.hadoop.hive.ql.UDF(老版本),现在继承GenericUDF

2)需要实现evaluate函数;evaluate函数支持重载;

3)在hive的命令行窗口创建函数

        a)打包后添加jar

                     add jar linux_jar_path

         b)创建function

                     create [temporary] function [dbname.]function_name AS class_name;

(4)在hive的命令行窗口删除函数

              Drop [temporary] function [if exists] [dbname.]function_name;

一、UDF函数的自定义

1、我们先来了解一下length()函数底层代码

(1)创建一个java工程,并创建一个lib文件夹

(2)使用hive编程需要的maven依赖

 
     
        org.apache.hive 
        hive-exec 
        2.3.8 
     

        或者可以将linux里Hive-2.3.8目录下lib里的jar包 copy到IDEA里java项目的lib目录下,然后add as library。

(3)实现求字符串长度的自定义函数(输入一个字符串,返回字符串的长度)

        按照上面的编程步骤做,首先继承GenericUDF,接着重写里面的方法(包括initialize初始化方法、evaluate业务逻辑核心方法、getDisplayString不需要关注)

类MyUDF.java:

import org.apache.hadoop.hive.ql.exec.UDFArgumentException;
import org.apache.hadoop.hive.ql.metadata.HiveException;
import org.apache.hadoop.hive.ql.udf.generic.GenericUDF;
import org.apache.hadoop.hive.serde2.objectinspector.ObjectInspector;
import org.apache.hadoop.hive.serde2.objectinspector.primitive.PrimitiveObjectInspectorFactory;

/**
 * 函数中可以传入参数,参数可能来自与一张表的字段
 * 也可能来自于我们自己写的常量
 * 目前我们自定义的函数要求只能是表中的字段 不能是常量
 */
public class MyUDF extends GenericUDF {
    /**
     * 函数的初始化  一般是用来校验参数的个数和参顺的类型
     * @param arguments    objectInspector函数的参数、数组
     * @return      函数返回值类型
     * @throws UDFArgumentException
     */
    @Override
    public ObjectInspector initialize(ObjectInspector[] arguments) throws UDFArgumentException {
        //校验参数的个数是否合法
        if (arguments.length !=1){
            throw new UDFArgumentException("该函数要求参数的个数只能为1个,你传入了"+arguments.length+"个参数");
        }

        //检验参数的类型是否合法
        //方法要求有一个返回值 返回值是我们的函数的返回值类型(int)
        return PrimitiveObjectInspectorFactory.javaIntObjectInspector;
    }

    /**
     * 真正的函数逻辑方法
     * @param arguments
     * @return
     * @throws HiveException
     */
    @Override
    public Object evaluate(DeferredObject[] arguments) throws HiveException {
        int length =  arguments[0].get().toString().length();
        return length;
    }

    @Override
    public String getDisplayString(String[] children) {
        return null;
    }
}

(4)打成jar包上传到HDFS文件系统

 hdfs dfs -put  /opt/data/jars/hf.jar

(5)创建临时函数与开发好的java class关联(若想持久使用就不要加temporary)

hive (default)> create temporary function my_len as "com.ly.MyUDF" using jar "hdfs://ip地址:9000/hf.jar";

如果报错类没有被找到那么使用如下命令清空jar包信息,重新登录Hive

        hive> list jars;

        hive> delete jar;

        hive> quit;

(6)接着查看关联成功的functions

hive (default)>show functions;

hive (default)>desc function myudf;

(7)然后我们就可以使用自定义的UDF函数啦

select myudf(name) from studentscore;    计算属性name其中值的长度

试错:

 【注意事项】(最好用临时函数)

   临时函数和永久函数的区别:

  1. 临时函数在当前hive命令行关闭后就不存在了
  2. 永久函数命令行关闭还存在
  3. 临时函数可以使用show function找到,但是永久函数无法使用该命令查询

    4、hive中自定义的函数和数据库是挂钩的,在某一个数据库创建的函数别的数据无法使用,除非你在这个数据库下再次创建一个函数。

二、UDTF函数的自定义

自定义UDTF函数的步骤和UDF一样。

要求:自定义一个 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;
import java.util.List;

public class MyUDTF extends GenericUDTF {
    //每一行的数据 数据可能是一列  也可能是多列
    private ArrayList outList = new ArrayList<>();

    @Override
    public StructObjectInspector initialize(StructObjectInspector argOIs) throws UDFArgumentException {
        //1.定义输出数据的列名和类型
        List fieldNames = new ArrayList<>();
        List fieldOIs = new ArrayList<>();
        //2.添加输出数据的列名和类型
        fieldNames.add("lineToWord");
        fieldOIs.add(PrimitiveObjectInspectorFactory.javaStringObjectInspector);
        return ObjectInspectorFactory.getStandardStructObjectInspector(fieldNames,
                fieldOIs);
    }

    @Override
    public void process(Object[] args) throws HiveException {
        //1.获取原始数据
        String arg = args[0].toString();
        //2.获取数据传入的第二个参数,此处为分隔符
        String splitKey = args[1].toString();
        //3.将原始数据按照传入的分隔符进行切分
        String[] fields = arg.split(splitKey);
        //4.遍历切分后的结果,并写出
        for (String field : fields) {
            //集合为复用的,首先清空集合
            outList.clear();
            //将每一个单词添加至集合
            outList.add(field);
            //将集合内容写出
            forward(outList);
        }
    }

    @Override
    public void close() throws HiveException {
    }
}

你可能感兴趣的:(HIVE,java,hive,big,data,java)