由于blog各种垃圾评论太多,而且本人审核评论周期较长,所以懒得管理评论了,就把评论功能关闭,有问题可以直接qq骚扰我

hive 自定义UDF函数

大数据 西门飞冰 730℃
[隐藏]

1.说明

Hive自带了一些函数,比如:max/min等,但是数量有限,碰到一些个性化业务需求,比如数据加密脱敏、URL解码、身份证校验、解析IP和手机号归属地,就可以通过自定义UDF来方便的扩展。

官方文档:https://cwiki.apache.org/confluence/display/Hive/HivePlugins

根据用户自定义函数类别分为以下三种:

(1)UDF(User-Defined-Function)

一进一出。

(2)UDAF(User-Defined Aggregation Function)

用户自定义聚合函数,多进一出。

类似于:count/max/min

(3)UDTF(User-Defined Table-Generating Functions)

用户自定义表生成函数,一进多出。

如lateral view explode()

2.编程步骤

(0)需求:自定义一个手机号脱敏需求

(1)pom导入hive依赖

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

(2)继承hive提供的类

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

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

(3)实现类中的抽象方法

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

import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class EncryptPhoneNumber extends GenericUDF {

    // 初始化方法,在真正执行计算之前会调用一次
    @Override
    public ObjectInspector initialize(ObjectInspector[] arguments) throws UDFArgumentException {

        if(arguments.length!=1){
            throw new UDFArgumentException("只能接收一个参数");
        }

        ObjectInspector argument = arguments[0];
        if(argument.getCategory()!=ObjectInspector.Category.PRIMITIVE){
            throw new UDFArgumentException("只能接收基本数据类型的参数");
        }

        PrimitiveObjectInspector primitiveObjectInspector = (PrimitiveObjectInspector) argument;
        if(primitiveObjectInspector.getPrimitiveCategory()!=PrimitiveObjectInspector.PrimitiveCategory.STRING){
            throw new UDFArgumentException("只能接收STRING类型的参数");
        }

        return PrimitiveObjectInspectorFactory.javaStringObjectInspector;
    }

    // 每行数据调用一下这个方法,数据的计算逻辑主要在这里实现
    @Override
    public Object evaluate(DeferredObject[] arguments) throws HiveException {
        DeferredObject argument = arguments[0];
        if (argument.get() != null) {
            String phone = argument.get().toString();
            //判断手机号是否为11位
            if (phone.length() == 11) {
                //判断数据是否满足中国大陆手机号码规范
                String regex = "^(1[3-9]\\d{9}$)";
                Pattern p = Pattern.compile(regex);
                Matcher m = p.matcher(phone);
                if (m.matches()) {
                    //进入这里都是符合手机号规则的
                    StringBuilder sb = new StringBuilder(phone);
                    sb.replace(3, 7, "xxxx");
                    return sb;
                } else {
                    //不符合手机号规则 数据直接原封不动返回
                    return phone;
                }
            } else {
                return phone;
            }
        }else{
            return null;
        }
    }

    // 自定义函数如果要在执行计划里面进行展示,就在这里定义要展示的内容,通常自定义函数没有展示需求
    @Override
    public String getDisplayString(String[] children) {
        return "这是hive自定义函数,实现手机号脱敏功能";
    }
}

3.服务侧配置

打成jar包上传到服务器/opt/module/hive/datas/EncryptPhoneNumber.jar

3.1.创建临时函数

1、将jar包添加到hive的classpath,临时生效

hive (default)> add jar /opt/module/hive/datas/EncryptPhoneNumber.jar;

2、创建临时函数与开发好的java class关联

hive (default)> create temporary function EncryptPhoneNumber as "com.fblinux.hive.udf.EncryptPhoneNumber";

3、即可在hql中使用自定义的临时函数

hive> select EncryptPhoneNumber(13511111111);
FAILED: SemanticException [Error 10014]: Line 1:7 Wrong arguments '13511111111': 只能接收STRING类型的参数
hive> select EncryptPhoneNumber("13511111111");
OK
135xxxx1111
hive> select EncryptPhoneNumber("23511111111");
OK
23511111111

4、删除临时函数

hive (default)> drop temporary function EncryptPhoneNumber;

注意:临时函数只跟会话有关系,跟库没有关系。只要创建临时函数的会话不断,在当前会话下,任意一个库都可以使用,其他会话全都不能使用。

3.2.创建永久函数

1、创建永久函数

注意:因为add jar本身也是临时生效,所以在创建永久函数的时候,需要制定路径(并且因为元数据的原因,这个路径还得是HDFS上的路径)。

hive (default)> 
create function EncryptPhoneNumber 
as "com.fblinux.hive.udf.EncryptPhoneNumber" 
using jar "hdfs://hadoop01:8020/udf/EncryptPhoneNumber.jar";

2、即可在hql中使用自定义的永久函数

hive> select EncryptPhoneNumber(13511111111);
FAILED: SemanticException [Error 10014]: Line 1:7 Wrong arguments '13511111111': 只能接收STRING类型的参数
hive> select EncryptPhoneNumber("13511111111");
OK
135xxxx1111
hive> select EncryptPhoneNumber("23511111111");
OK
23511111111

3、删除永久函数

hive (default)> drop function EncryptPhoneNumber;

注意:永久函数跟会话没有关系,创建函数的会话断了以后,其他会话也可以使用。

永久函数创建的时候,在函数名之前需要自己加上库名,如果不指定库名的话,会默认把当前库的库名给加上。

永久函数使用的时候,需要在指定的库里面操作,或者在其他库里面使用的话加上,库名.函数名。

3.3.执行计划内容验证

hive> explain select EncryptPhoneNumber("13511111111");
OK
STAGE DEPENDENCIES:
  Stage-0 is a root stage

STAGE PLANS:
  Stage: Stage-0
    Fetch Operator
      limit: -1
      Processor Tree:
        TableScan
          alias: _dummy_table
          Row Limit Per Split: 1
          Statistics: Num rows: 1 Data size: 10 Basic stats: COMPLETE Column stats: COMPLETE
          Select Operator
            expressions: 这是hive自定义函数,实现手机号脱敏功能 (type: string)
            outputColumnNames: _col0
            Statistics: Num rows: 1 Data size: 95 Basic stats: COMPLETE Column stats: COMPLETE
            ListSink

4.知识点

1、要是在自定义函数场景中碰到自己不会写的功能,可以通过如下方式,查询hive自带的函数在源码的路径,进行参考

hive> desc function extended upper;
OK
upper(str) - Returns str with all characters changed to uppercase
Synonyms: ucase
Example:
  > SELECT upper('Facebook') FROM src LIMIT 1;
  'FACEBOOK'
Function class:org.apache.hadoop.hive.ql.udf.generic.GenericUDFUpper	//hive 自带函数源码的位置
Function type:BUILTIN

2、hive 自定义函数在idea写完之后,要进行测试,需要自己写单元测试并造用例

转载请注明:西门飞冰的博客 » hive 自定义UDF函数

喜欢 (0)or分享 (0)