tencent cloud

文档反馈

自定义函数 UDF

最后更新时间:2024-10-30 11:37:10
    本文为您介绍自定义函数 ( UDF ) 及开发和使用流程。

    UDF 分类

    UDF 分类
    描述
    UDF(User Defined Scalar Function)
    自定义标量函数,通常称为 UDF 。其输入与输出是一对一的关系,即读入一行数据,写出一条输出值。
    UDTF(User Defined Table-valued Function)
    自定义表值函数,用来解决一次函数调用输出多行数据场景的,也是唯一一个可以返回多个字段的自定义函数。
    UDAF(User Defined Aggregation Function)
    自定义聚合函数,其输入与输出是多对一的关系,即将多条输入记录聚合成一条输出值,可以与 SQL 中的 Group By 语句联合使用。
    更多说明可参考社区文档:UDFUDAFUDTF

    开发 UDF

    使用 IDE,创建 Maven 工程。工程基本信息如下,您可以自定义 groupId 和 artifactId :
    <groupId>org.example</groupId>
    <artifactId>hive-udf</artifactId>
    <version>1.0-SNAPSHOT</version>
    <packaging>jar</packaging>
    添加 pom 依赖:
    <!-- https://mvnrepository.com/artifact/org.apache.hive/hive-exec -->
    <dependency>
    <groupId>org.apache.hive</groupId>
    <artifactId>hive-exec</artifactId>
    <version>3.1.3</version>
    <exclusions>
    <exclusion>
    <groupId>org.pentaho</groupId>
    <artifactId>*</artifactId>
    </exclusion>
    </exclusions>
    </dependency>
    创建一个类,类名您可以自定义,本文以 nvl 为例:
    方式 1:继承 UDF 重写 evaluate 方法:
    package org.example;
    
    import org.apache.hadoop.hive.ql.exec.UDF;
    
    public class nvl extends UDF {
    public String evaluate(final String s) {
    if (s == null) { return null; }
    return s + ":HelloWorld";
    }
    }
    方式 2(推荐,适用于传参情况复杂的场景):继承 GenericUDF 重写 initialize、evaluate、getDisplayString:
    package org.example;
    
    import org.apache.hadoop.hive.ql.exec.Description;
    import org.apache.hadoop.hive.ql.exec.UDFArgumentException;
    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.ql.udf.generic.GenericUDFUtils;
    import org.apache.hadoop.hive.serde2.objectinspector.ObjectInspector;
    
    @Description(name = "nvl",
    value = "nvl(value, default_value) - Returns default value if value is null else returns value",
    extended = "Example: SELECT nvl(null, default_value);")
    public class MyUDF extends GenericUDF {
    
    private GenericUDFUtils.ReturnObjectInspectorResolver returnOIResolver;
    private ObjectInspector[] argumentOIs;
    
    /**
    * 根据函数的入参类型确定出参类型
    */
    public ObjectInspector initialize(ObjectInspector[] arguments) throws UDFArgumentException {
    argumentOIs = arguments;
    if(arguments.length != 2) {
    throw new UDFArgumentException("The operator 'NVL' accepts 2 arguments.");
    }
    returnOIResolver = new GenericUDFUtils.ReturnObjectInspectorResolver(true);
    if(!(returnOIResolver.update(arguments[0]) && returnOIResolver.update(arguments[1]))) {
    throw new UDFArgumentTypeException(2, "The 1st and 2nd args of function NLV should have the same type, "
    + "but they are different: \\""+arguments[0].getTypeName()+"\\" and \\"" + arguments[1].getTypeName() + "\\"");
    }
    return returnOIResolver.get();
    }
    
    /**
    * 计算结果,最后结果的数据类型会根据initialize方法的返回值类型确定函数的返回值类型
    */
    public Object evaluate(DeferredObject[] arguments) throws HiveException {
    Object retVal = returnOIResolver.convertIfNecessary(arguments[0].get(), argumentOIs[0]);
    if(retVal == null) {
    retVal = returnOIResolver.convertIfNecessary(arguments[1].get(), argumentOIs[1]);
    }
    return retVal;
    }
    
    /**
    * 获取要在explain中显示的字符串
    */
    public String getDisplayString(String[] children) {
    StringBuilder builder = new StringBuilder();
    builder.append("if ");
    builder.append(children[0]);
    builder.append(" is null ");
    builder.append("returns ");
    builder.append(children[1]);
    return builder.toString();
    }
    }
    以方式 2 为例,将自定义的代码打成 jar 包。在 pom.xml 所在目录,执行如下命令制作 jar 包。
    mvn clean package -DskipTests
    target 目录下会出现 hive-udf-1.0-SNAPSHOT.jar 的 jar 包,即代表完成了 UDF 开发工作。

    使用UDF

    将生产的 jar 上传至 EMR 集群 Master 节点:
    scp ./target/hive-udf-1.0-SNAPSHOT.jar root@${master_public_ip}:/usr/local/service/hive
    切换 hadoop 用户并执行以下命令将 jar 上传到 HDFS 中:
    su hadoop
    hadoop fs -put ./hive-udf-1.0-SNAPSHOT.jar /
    查看上传到 HDFS 中的 jar:
    hadoop fs -ls /
    Found 5 items
    drwxr-xr-x - hadoop supergroup 0 2023-08-22 09:20 /data
    drwxrwx--- - hadoop supergroup 0 2023-08-22 09:20 /emr
    -rw-r--r-- 2 hadoop supergroup 3235 2023-08-22 15:39 /hive-udf-1.0-SNAPSHOT.jar
    drwx-wx-wx - hadoop supergroup 0 2023-08-22 09:20 /tmp
    drwxr-xr-x - hadoop supergroup 0 2023-08-22 09:20 /user
    连接 Hive:
    hive
    执行以下命令,应用生成的 JAR 包创建函数。
    hive> create function nvl as "org.example.MyUDF" using jar "hdfs:///hive-udf-1.0-SNAPSHOT.jar";
    说明:
    1. nvl 是 UDF 函数的名称。
    2. org.example.MyUDF 是项目中创建的类全名。
    3. hdfs:///user/hive/warehouse/hiveudf-1.0-SNAPSHOT.jar 为上传 jar 包到 HDFS 的路径。
    出现以下信息时,表示创建成功:
    Added [/data/emr/hive/tmp/1b0f12a6-3406-4700-8227-37dec721297b_resources/hive-udf-1.0-SNAPSHOT.jar] to class path
    Added resources: [hdfs:///hive-udf-1.0-SNAPSHOT.jar]
    OK
    Time taken: 1.549 seconds
    您也可以通过命令 SHOW FUNCTIONS LIKE '*nvl*',验证函数是否创建成功。
    执行以下命令,使用 UDF 函数。该函数与内置函数使用方式一样,直接使用函数名称即可访问:
    hive> select nvl("tur", "def");
    OK
    tur
    Time taken: 0.344 seconds, Fetched: 1 row(s)
    hive> select nvl(null, "def");
    OK
    def
    Time taken: 0.471 seconds, Fetched: 1 row(s)
    
    联系我们

    联系我们,为您的业务提供专属服务。

    技术支持

    如果你想寻求进一步的帮助,通过工单与我们进行联络。我们提供7x24的工单服务。

    7x24 电话支持