全部產品
Search
文件中心

MaxCompute:UDF開發(Java)

更新時間:Jun 19, 2024

當MaxCompute提供的內建函數無法支撐您的業務實現時, 您可以根據本文提供的開發流程,使用開發工具(例如IntelliJ IDEA(Maven)或MaxCompute Studio)自行編寫代碼邏輯建立自訂函數(UDF),並在MaxCompute中進行調用,以滿足多樣化業務需求。本文為您介紹如何通過Java語言編寫UDF。

使用限制

  • 訪問外網

    MaxCompute預設不支援通過自訂函數訪問外網。如果您需要通過自訂函數訪問外網,請根據業務情況填寫並提交網路連接申請表單,MaxCompute支援人員團隊會及時聯絡您完成網路開通操作。表單填寫指導,請參見網路開通流程

  • 訪問VPC網路

    MaxCompute預設不支援通過UDF訪問VPC網路。如果您的UDF涉及訪問VPC網路中的資源時,需要先建立MaxCompute與目標VPC網路間的網路連接,才可以直接通過UDF訪問VPC網路中的資源,操作詳情請參見通過UDF訪問VPC網路資源

  • 讀取表資料

    目前版本不支援使用UDF/UDAF/UDTF讀取以下情境的表資料:

    • 做過表結構修改(Schema Evolution)的表資料。

    • 包含複雜資料類型的表資料。

    • 包含JSON資料類型的表資料。

    • Transactional表的表資料。

注意事項

在編寫Java UDF前,您需要先瞭解UDF代碼結構,以及Java 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值,不允許使用。

UDF開發流程

開發UDF時通常需進行準備工作、編寫UDF代碼、上傳並註冊UDF、調試UDF這幾個步驟。同時MaxCompute支援多種工具,以下以常見的MaxCompute Studio、DataWorks、odpscmd三種工具為例,以一個具體的樣本為您介紹UDF開發的通用流程。

使用MaxCompute Studio

以下以開發一個字元小寫轉換功能的UDF為例,為您介紹使用MaxCompute Studio開發並調用Java UDF的操作步驟如下。

  1. 準備工作。

    使用MaxCompute Studio開發調試UDF時,您需要先安裝MaxCompute Studio並串連MaxCompute專案,做好UDF開發前準備工作。操作詳情請參見:

    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鍵。

      選擇類型填寫名稱

      Name為建立的MaxCompute Java Class名稱。如果還沒有建立Package,在此處填寫packagename.classname,會自動產生Package。本樣本建立的Java Class名稱為Lower

    3. 在代碼編寫地區開始開發UDF代碼。代碼編輯地區UDF程式碼範例如下。

      package com.aliyun.odps.udf.example;
      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. 上傳並註冊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. 調試UDF。

    在左側導覽列單擊Project Explore,在目標MaxCompute專案上單擊右鍵,選擇Open Console並在Console地區輸入調用UDF的SQL語句,按Enter鍵運行即可。調用UDFSQL語句樣本如下。

    select lower_test('ABC');

    返回結果如下。

    +-----+
    | _c0 |
    +-----+
    | abc |
    +-----+

使用DataWorks

  1. 準備工作。

    使用DataWorks開發調試UDF時,您需要先開通DataWorks並綁定MaxCompute專案,做好UDF開發前準備工作。操作詳情請參見使用DataWorks串連

  2. 編寫UDF代碼。

    您可以在任意Java開發工具中開發UDF代碼並打包為一個JAR包。您可以使用以下UDF程式碼範例。

    package com.aliyun.odps.udf.example;
    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();
        }
    }
  3. 上傳並註冊UDF。

    您可以將已打包好的程式碼封裝通過DataWorks上傳並完成UDF註冊,操作詳情請參見:

    1. 建立並使用MaxCompute資源

    2. 建立並使用MaxCompute函數

  4. 調試UDF。

    註冊完成UDF後,您可以建立一個ODPS SQL節點,在節點中編寫並建立SQL命令來調試UDF。建立ODPS SQL節點的操作請參見建立ODPS SQL節點,調試命令樣本如下。

    select lower_test('ABC');

使用odpscmd

  1. 準備工作。

    使用odpscmd開發調試UDF時,您需要先下載安裝odpscmd工具,並配置config檔案串連MaxCompute專案,做好UDF開發前準備工作。操作詳情請參見使用用戶端(odpscmd)串連

  2. 編寫UDF代碼。

    您可以在任意Java開發工具中開發UDF代碼並打包為一個JAR包。您可以使用以下UDF程式碼範例。

    package com.aliyun.odps.udf.example;
    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();
        }
    }
  3. 上傳並註冊UDF。

    您可以將已打包好的程式碼封裝通過odpscmd上傳並完成UDF註冊,操作詳情請參見:

    1. ADD JAR

    2. CREATE FUNCTION

  4. 調試UDF。

    註冊完成UDF後,您可以編寫並建立SQL命令來調試UDF。調試命令樣本如下。

    select lower_test('ABC');

UDF開發完成後:UDF調用說明

按照上述UDF開發流程,完成Java UDF開發後,您即可在odpscmd中通過MaxCompute SQL調用Java UDF。調用方法如下:

  • 在歸屬MaxCompute專案中使用自訂函數:使用方法與內建函數類似,您可以參照內建函數的使用方法使用自訂函數。

  • 跨專案使用自訂函數:即在專案A中使用專案B的自訂函數,跨專案分享語句樣本:select B:udf_in_other_project(arg0, arg1) as res from table_t;。更多跨專案分享資訊,請參見基於Package跨專案訪問資源

UDF樣本demo

附錄:UDF代碼結構

您可以使用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相容資料類型

附錄:資料類型

資料類型映射

為確保編寫Java UDF過程中使用的資料類型與MaxCompute支援的資料類型保持一致,您需要關注二者間的資料類型映射關係。具體映射關係如下。

說明

在MaxCompute中不同資料類型版本支援的資料類型不同。從MaxCompute 2.0版本開始,擴充了更多的新資料類型,同時還支援ARRAY、MAP、STRUCT等複雜類型。更多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

DATE

java.sql.Date

DateWritable

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

不涉及

Hive相容資料類型

當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樣本