本文为您介绍如何通过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 TypeJava TypeJava Writable Type
TINYINTjava.lang.ByteByteWritable
SMALLINTjava.lang.ShortShortWritable
INTjava.lang.IntegerIntWritable
BIGINTjava.lang.LongLongWritable
FLOATjava.lang.FloatFloatWritable
DOUBLEjava.lang.DoubleDoubleWritable
DECIMALjava.math.BigDecimalBigDecimalWritable
BOOLEANjava.lang.BooleanBooleanWritable
STRINGjava.lang.StringText
VARCHARcom.aliyun.odps.data.VarcharVarcharWritable
BINARYcom.aliyun.odps.data.BinaryBytesWritable
DATEjava.sql.Date  DateWritable
DATETIMEjava.util.DateDatetimeWritable
TIMESTAMPjava.sql.TimestampTimestampWritable
INTERVAL_YEAR_MONTH不涉及IntervalYearMonthWritable
INTERVAL_DAY_TIME不涉及IntervalDayTimeWritable
ARRAYjava.util.List不涉及
MAPjava.util.Map不涉及
STRUCTcom.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 |
    +-----+