本文为您介绍如何通过Java语言编写UDF。

UDF代码结构

您可以通过IntelliJ IDEA(Maven)或MaxCompute Studio工具使用Java语言编写UDF代码,代码中需要包含如下信息:
  • Java包(Package):可选。

    您可以将定义的Java类打包,为后续查找和使用类提供方便。

  • 继承UDF类:必选。

    必需携带的UDF类为com.aliyun.odps.udf.UDF。当您需要使用其他UDF类或者需要用到复杂数据类型时,请根据MaxCompute SDK添加需要的类。例如STRUCT数据类型对应的UDF类为com.aliyun.odps.data.Struct

  • @Resolve注解:可选。

    格式为@Resolve(<signature>)signature用于定义函数的输入参数和返回值的数据类型。当您需要在UDF中使用STRUCT数据类型时,无法基于com.aliyun.odps.data.Struct反射分析得到Field Name和Field Type,所以需要用@Resolve注解来辅助获取。即如果您需要在UDF中使用STRUCT,请在UDF Class中加上@Resolve注解,注解只会影响参数或返回值中包含com.aliyun.odps.data.Struct的重载。例如@Resolve("struct<a:string>,string->string")。详细使用示例,请参见复杂数据类型示例

  • 自定义Java类:必选。

    UDF代码的组织单位,定义了实现业务需求的变量及方法。

  • evaluate方法:必选。

    非静态的Public方法,位于自定义的Java类中。evaluate方法的输入参数和返回值的数据类型将作为SQL语句中UDF的函数签名Signature(定义UDF的输入与输出数据类型)。

    您可以在UDF中实现多个evaluate方法,在调用UDF时,MaxCompute会依据UDF调用的参数类型匹配正确的evaluate方法。

    编写Java UDF时可以使用Java Type或Java Writable Type,MaxCompute项目支持处理的数据类型与Java数据类型的详细映射关系,请参见数据类型

  • UDF初始化或结束代码:可选。您可以通过void setup(ExecutionContext ctx)void close()分别实现UDF初始化和结束。void setup(ExecutionContext ctx)方法会在evaluate方法前调用且仅会调用一次,可以用来初始化一些计算所需要的资源或类的成员对象。void close()方法会在evaluate方法结束后调用,可以用来执行一些清理工作,例如关闭文件。
UDF代码示例如下。
  • 使用Java Type类型
    //将定义的Java类组织在org.alidata.odps.udf.examples包中。
    package org.alidata.odps.udf.examples;  
    //继承UDF类。
    import com.aliyun.odps.udf.UDF;         
    //自定义Java类。
    public final class Lower extends UDF { 
    //evaluate方法。其中:String标识输入参数的数据类型,return标识返回值。
        public String evaluate(String s) { 
            if (s == null) { 
            return null; 
        } 
            return s.toLowerCase(); 
      } 
    }
  • 使用Java Writable Type类型
    //将定义的Java类组织在com.aliyun.odps.udf.example包中。
    package com.aliyun.odps.udf.example;
    //添加Java Writable Type类型必需的类。
    import com.aliyun.odps.io.Text;
    //继承UDF类。
    import com.aliyun.odps.udf.UDF;
    //自定义Java类。
    public class MyConcat extends UDF {
      private Text ret = new Text();
    //evaluate方法。其中:Text标识输入参数的数据类型,return标识返回值。
      public Text evaluate(Text a, Text b) {
          if (a == null || b == null) {
          return null;
        }
          ret.clear();
          ret.append(a.getBytes(), 0, a.getLength());
          ret.append(b.getBytes(), 0, b.getLength());
          return ret;
      }
    }

MaxCompute还支持直接使用在其兼容的Hive版本上开发的UDF,请参见兼容Hive UDF

使用限制

不支持通过自定义函数访问外网。如果您需要通过自定义函数访问外网,请根据业务情况填写并提交网络连接申请表单,MaxCompute技术支持团队会及时联系您完成网络开通操作。表单填写指导,请参见网络开通流程

注意事项

在编写Java UDF时,您需要注意:
  • 不同UDF JAR包中不建议存在类名相同但实现逻辑不一样的类。例如UDF1、UDF2分别对应资源JAR包udf1.jar、udf2.jar,两个JAR包里都包含名称为com.aliyun.UserFunction.class的类但实现逻辑不一样,当同一条SQL语句中同时调用UDF1和UDF2时,MaxCompute会随机加载其中一个类,此时会导致UDF执行结果不符合预期甚至编译失败。
  • Java UDF中输入或返回值的数据类型是对象,数据类型首字母必须大写,例如String。
  • SQL中的NULL值通过Java中的NULL表示。Java Primitive Type无法表示SQL中的NULL值,不允许使用。

数据类型

在MaxCompute中不同数据类型版本支持的数据类型不同。从MaxCompute 2.0版本开始,扩展了更多的新数据类型,同时还支持ARRAY、MAP、STRUCT等复杂类型。更多MaxCompute数据类型版本信息,请参见数据类型版本说明

为确保编写Java UDF过程中使用的数据类型与MaxCompute支持的数据类型保持一致,您需要关注二者间的数据类型映射关系。具体映射关系如下。

MaxCompute Type Java Type Java Writable Type
TINYINT java.lang.Byte ByteWritable
SMALLINT java.lang.Short ShortWritable
INT java.lang.Integer IntWritable
BIGINT java.lang.Long LongWritable
FLOAT java.lang.Float FloatWritable
DOUBLE java.lang.Double DoubleWritable
DECIMAL java.math.BigDecimal BigDecimalWritable
BOOLEAN java.lang.Boolean BooleanWritable
STRING java.lang.String Text
VARCHAR com.aliyun.odps.data.Varchar VarcharWritable
BINARY com.aliyun.odps.data.Binary BytesWritable
DATETIME java.util.Date DatetimeWritable
TIMESTAMP java.sql.Timestamp TimestampWritable
INTERVAL_YEAR_MONTH 不涉及 IntervalYearMonthWritable
INTERVAL_DAY_TIME 不涉及 IntervalDayTimeWritable
ARRAY java.util.List 不涉及
MAP java.util.Map 不涉及
STRUCT com.aliyun.odps.data.Struct 不涉及

当您需要在Java UDF中使用复杂数据类型时,使用示例请参见复杂数据类型示例

说明 当MaxCompute项目采用MaxCompute 2.0数据类型版本时,UDF的输入或返回值才可以使用Java Writable Type。

使用说明

按照开发流程,完成Java UDF开发后,您即可通过MaxCompute SQL调用Java UDF。调用方法如下:
  • 在归属MaxCompute项目中使用自定义函数:使用方法与内建函数类似,您可以参照内建函数的使用方法使用自定义函数。
  • 跨项目使用自定义函数:即在项目A中使用项目B的自定义函数,跨项目分享语句示例:select B:udf_in_other_project(arg0, arg1) as res from table_t;。更多跨项目分享信息,请参见基于Package的跨项目空间资源访问

使用MaxCompute Studio完整开发及调用Java UDF的操作,请参见使用示例

兼容Hive UDF

当MaxCompute项目采用2.0数据类型版本时,支持Hive风格的UDF,您可以直接使用在MaxCompute兼容的Hive版本上开发的Hive UDF。

MaxCompute兼容的Hive版本为2.1.0,对应Hadoop版本为2.7.2。如果UDF是在其他版本的Hive或Hadoop上开发的,您需要使用兼容的Hive或Hadoop版本重新编译UDF JAR包。

在MaxCompute上使用Hive UDF的具体案例,请参见兼容Hive Java UDF示例

使用示例

以通过MaxCompute Studio开发字符小写转换功能的UDF为例,开发并调用Java UDF的操作步骤如下:

  1. 在IntelliJ IDEA上完成如下准备工作:
    1. 安装MaxCompute Studio
    2. 创建MaxCompute项目连接
    3. 创建MaxCompute Java Module
  2. 编写UDF代码。
    1. Project区域,右键单击Module的源码目录(即src > main > java),选择new > MaxCompute Java新建Java Class
    2. Create new MaxCompute java class对话框,单击UDF并填写Name后,按Enter键。例如Java Class名称为Lower。选择类型填写名称

      Name为创建的MaxCompute Java Class名称。如果还没有创建Package,在此处填写packagename.classname,会自动生成Package。

    3. 在代码编写区域写入如下代码。代码编辑区域UDF代码示例如下。
      package <packagename>;
      import com.aliyun.odps.udf.UDF;
      public final class Lower extends UDF {
          public String evaluate(String s) {
              if (s == null) { 
                 return null; 
              }
                 return s.toLowerCase();
          }
      }
      说明 如果需要本地调试Java UDF,请参见开发和调试UDF
  3. 注册MaxCompute UDF。
    在UDF Java文件上单击右键,选择Deploy to server...,在Package a jar, submit resource and register function对话框中配置如下参数后,单击OK注册UDF
    • MaxCompute project:UDF所在的MaxCompute项目名称。由于UDF本身是在连接的MaxCompute项目下编写的,此处保持默认值即可。
    • Resource file:UDF依赖的资源文件路径。此处保持默认值即可。
    • Resource name:UDF依赖的资源。此处保持默认值即可。
    • Function name:注册的函数名称,即后续SQL中调用的UDF名称。例如Lower_test。
  4. 在左侧导航栏单击Project Explore,在目标MaxCompute项目上单击右键,选择Open in Console并在Console区域输入调用UDF的SQL语句,按Enter键运行即可。调用UDFSQL语句示例如下。
    select lower_test('ABC');
    返回结果如下。
    +-----+
    | _c0 |
    +-----+
    | abc |
    +-----+