【大数据之Hive】十七、Hive-HQL函数之自定义函数

1 概述

  当Hive提供的内置函数无法满足业务处理需求时,可以通过自定义UDF函数来扩展。

用户自定义函数类别:
(1)UDF(User-Defined-Function):一进一出。
(2)UDAF(User-Defined Aggregation Function):用户自定义聚合函数,多进一出。类似于:count/max/min
(3)UDTF(User-Defined Table-Generating Functions):用户自定义表生成函数,一进多出。如lateral view explode()。

自定义函数步骤:
(1)继承Hive提供的类:

org.apache.hadoop.hive.ql.udf.generic.GenericUDF
org.apache.hadoop.hive.ql.udf.generic.GenericUDTF

(2)实现类中的抽象方法:
(3)在hive的命令行窗口创建函数:

--添加jar,添加到hive的节点
add jar linux_jar_path;

--创建function
create [temporary] function[dbname.]function_name AS class_name;

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

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

2 自定义UDF函数(例子)

需求:自定义UDF实现计算给定基本数据类型的长度,例如:

select my_len("asdf");    --4

步骤:
(1)创建一个Maven工程HiveDemo,在pom.xml中导入依赖

<dependencies>
   <dependency>
      <groupId>org.apache.hive</groupId>
      <artifactId>hive-exec</artifactId>
      <version>3.1.3</version>
   </dependency>
</dependencies>

(2)创建一个类

package org.example.hive.stady.udf;

import org.apache.hadoop.hive.ql.exec.UDFArgumentException;
import org.apache.hadoop.hive.ql.exec.UDFArgumentLengthException;
import org.apache.hadoop.hive.ql.exec.UDFArgumentTypeException;
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.PrimitiveObjectInspector;
import org.apache.hadoop.hive.serde2.objectinspector.primitive.PrimitiveObjectInspectorFactory;

public class MyLength extends GenericUDF {

    /**
     * 初始化,在运行sql语句时调用自定义函数之前调用一次
     * 判断传进来的参数的类型和长度
     * 约定返回的数据类型
     */
    @Override
    public ObjectInspector initialize(ObjectInspector[] arguments) throws UDFArgumentException {
        // ObjectInspector为对象检查器

        //利用数组长度来校验函数接收参数的个数
        if (arguments.length != 1) {
            throw new UDFArgumentLengthException("只接收一个参数");
        }

        //校验参数的类型是不是基本数据类型
        ObjectInspector argument = arguments[0];
        if (!argument.getCategory().equals(ObjectInspector.Category.PRIMITIVE)) {
            throw new UDFArgumentTypeException(1, "只接收基本数据类型参数");
        }

        //将基本数据类型强转为PrimitiveObjectInspector
        PrimitiveObjectInspector primitiveObjectInspector = (PrimitiveObjectInspector) argument;
        if (primitiveObjectInspector.getPrimitiveCategory() != PrimitiveObjectInspector.PrimitiveCategory.STRING) {
            throw new UDFArgumentTypeException(1, "只接收string类型参数");
        }

        return PrimitiveObjectInspectorFactory.javaIntObjectInspector;
    }

    /**
     * 核心处理逻辑,每处理一行数据就调用一次evaluate方法
     * 解决具体逻辑的
     */
    @Override
    public Object evaluate(DeferredObject[] arguments) throws HiveException {
        //DeferredObject是hive中的懒加载的类,拿到数据需要get一下。
        DeferredObject argument = arguments[0];   //直接用,因为在初始化时已经校验过参数个数,不会发生数组越界问题
        Object o = argument.get();

        if (o == null)
            return 0;
        else return
                o.toString().length();
    }

    // 用于获取(执行计划中的及sql中 explain)解释的字符串
    @Override
    public String getDisplayString(String[] strings) {
        return null;
    }
}

(3)创建临时函数(只在当前会话有效)
  打成jar包上传到(hive的节点上)服务器/opt/module/hive/datas/下。

--将jar包添加到hive的classpath,临时生效:
add jar /opt/module/hive/datas/MyLength.jar;

--创建临时函数与开发好的java class关联:
create temporary function my_len as "org.example.hive.stady.udf. MyLength";
        
--查看函数,如果存在可以当作内置函数直接使用:
show functions like “my_len”;

--传值测试:
select my_len(“asdf”);
    
--删除临时函数:
drop temporary function my_len;

  临时函数只跟会话有关系,跟库没有关系。只要创建临时函数的会话不断,在当前会话下,任意一个库都可以使用,其他会话全都不能使用。
(4)创建永久函数
  因为add jar本身也是临时生效且使用元数据,所以在创建永久函数的时候,需要指定HDFS路径。

  先把jar包上传到HDFS指定路径下

--创建永久函数
create function my_len as " org.example.hive.stady.udf. MyLength " using jar "hdfs://hadoop102:8020/udf/ MyLength.jar ";

--查看函数,如果存在可以当作内置函数直接使用,结果显示:数据库名.my_len
show functions like “*my_len*;

--传值测试:
select 数据库名.my_len(“asdf”);

--删除永久函数:
drop function my_len;

永久函数跟会话没有关系,创建函数的会话断了以后,其他会话也可以使用。
永久函数创建的时候,在函数名之前需要自己加上库名,如果不指定库名的话,会默认把当前库的库名给加上。
永久函数使用的时候,需要在指定的库里面操作,或者在其他库里面使用的话加上,库名.函数名。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值