全部產品
Search
文件中心

MaxCompute:Java UDTF

更新時間:Sep 21, 2024

採用Java語言編寫UDTF函數可有效處理複雜資料處理任務並自訂邏輯,並且通過合理利用Java語言的特性,能更好地滿足特定的資料處理需求,提升開發效率和處理效能。本文將介紹UDTF函數的代碼結構、使用說明和樣本。

UDTF代碼結構

您可以通過IntelliJ IDEA(Maven)或MaxCompute Studio工具使用Java語言編寫UDTF代碼,代碼中需要包含如下資訊:

  • Java包(Package):可選。

    您可以將定義的Java類打包,為後續尋找和使用類提供方便。

  • 繼承UDTF類:必選。

    必須攜帶的UDTF類為com.aliyun.odps.udf.UDTFcom.aliyun.odps.udf.annotation.Resolve(對應@Resolve註解)和com.aliyun.odps.udf.UDFException(對應實現Java類的方法)。當您需要使用其他UDTF類或者需要用到複雜資料類型時,請根據MaxCompute UDF概述添加需要的類。

  • 自訂Java類:必選。

    UDTF代碼的組織單位,定義了實現業務需求的變數及方法。

  • @Resolve註解:必選。

    格式為@Resolve(<signature>)signature為函數簽名,用於定義函數的輸入參數和傳回值的資料類型。UDTF無法通過反射分析擷取函數簽名,只能通過@Resolve註解方式擷取函數簽名,例如@Resolve("smallint->varchar(10)")。更多@Resolve註解資訊,請參見@Resolve註解

  • 實現Java類的方法:必選。

    Java類實現包含如下4個方法,您可以根據實際需要進行選擇。

    介面定義

    描述

    public void setup(ExecutionContext ctx) throws UDFException

    初始化方法,在UDTF處理輸入的資料前,MaxCompute會調用使用者自訂的初始化行為。在每個Worker內setup會被先調用一次。

    public void process(Object[] args) throws UDFException

    SQL中每一條記錄都會對應調用一次processprocess的參數為SQL語句中指定的UDTF輸入參數。輸入參數以Object[]的形式傳入,輸出結果通過forward函數輸出。您需要在process函數內自行調用forward,以決定輸出資料。

    說明

    當未使用processclose方法觸發forward調用時,可能會導致資料丟失,請務必謹慎使用,以避免出現此情況。例如:通過後台線程執行了forward調用,此時一定要確保process方法在forward調用結束後再結束,否則可能導致資料丟失。

    public void close() throws UDFException

    UDTF的結束方法。只會被調用一次,即在處理完最後一條記錄之後被調用。

    public void forward(Object …o) throws UDFException

    調用forward方法輸出資料,每調用一次forward代表輸出一條記錄。在SQL查詢語句中調用UDTF時,可以通過as子句將forward輸出的結果進行重新命名。

    編寫Java UDTF時可以使用Java Type或Java Writable Type,MaxCompute專案支援處理的資料類型與Java資料類型的詳細映射關係,請參見資料類型

UDTF程式碼範例如下。

//將定義的Java類組織在org.alidata.odps.udtf.examples包中。
package org.alidata.odps.udtf.examples;
//繼承UDTF類。
import com.aliyun.odps.udf.UDTF;
import com.aliyun.odps.udf.UDTFCollector;
import com.aliyun.odps.udf.annotation.Resolve;
import com.aliyun.odps.udf.UDFException;
//自訂Java類。  
//@Resolve註解。
@Resolve("string,bigint->string,bigint")
public class MyUDTF extends UDTF {     
     //實現Java類的方法。
     @Override
     public void process(Object[] args) throws UDFException {
         String a = (String) args[0];
         Long b = (Long) args[1];
         for (String t: a.split("\\s+")) {
         forward(t, b);
       }
     }
   }

使用限制

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

  • select語句中使用UDTF時,不允許存在其他列或運算式。錯誤樣本如下。

    --查詢語句中同時攜帶了UDTF和其他列。
    select value, user_udtf(key) as mycol ...
  • UDTF不能嵌套使用。錯誤樣本如下。

    --user_udtf1嵌套了user_udtf2,不允許嵌套。
    select user_udtf1(user_udtf2(key)) as mycol...;
  • 不支援在同一個select子句中與group bydistribute bysort by聯用。錯誤樣本如下。

    --UDTF不能與group by聯用。
    select user_udtf(key) as mycol ... group by mycol;

注意事項

在編寫Java UDTF時,您需要注意:

  • 不同UDTF JAR包中不建議存在類名相同但實現邏輯不一樣的類。例如UDTF1、UDTF2分別對應資源JAR包udtf1.jar、udtf2.jar,兩個JAR包裡都包含名稱為com.aliyun.UserFunction.class的類但實現邏輯不一樣,當同一條SQL語句中同時調用UDTF1和UDTF2時,MaxCompute會隨機載入其中一個類,此時會導致UDTF執行結果不符合預期甚至編譯失敗。

  • Java UDTF中輸入或傳回值的資料類型是對象,資料類型首字母必須大寫,例如String。

  • SQL中的NULL值通過Java中的NULL表示。Java Primitive Type無法表示SQL中的NULL值,不允許使用。

@Resolve註解

@Resolve註解格式如下。

@Resolve(<signature>)

signature為函數簽名字串,用於標識輸入參數和傳回值的資料類型。執行UDTF時,UDTF函數的輸入參數和傳回值類型要與函數簽名指定的類型一致。查詢語義解析階段會檢查不符合函數簽名定義的用法,檢查到類型不符時會報錯。具體格式如下。

'arg_type_list -> type_list'

其中:

  • type_list:表示傳回值的資料類型。UDTF可以返回多列。支援的資料類型為:BIGINT、STRING、DOUBLE、BOOLEAN、DATETIME、DECIMAL、FLOAT、BINARY、DATE、DECIMAL(precision,scale)、複雜資料類型(ARRAY、MAP、STRUCT)或複雜資料類型嵌套。

  • arg_type_list:表示輸入參數的資料類型。輸入參數可以為多個,用英文逗號(,)分隔。支援的資料類型為BIGINT、STRING、DOUBLE、BOOLEAN、DATETIME、DECIMAL、FLOAT、BINARY、DATE、DECIMAL(precision,scale)、CHAR、VARCHAR、複雜資料類型(ARRAY、MAP、STRUCT)或複雜資料類型嵌套。

    arg_type_list還支援星號(*)或為空白(''):

    • arg_type_list為星號(*)時,表示輸入參數為任意個數。

    • arg_type_list為空白('')時,表示無輸入參數。

    更多Resolve註解文法擴充詳情,請參見UDAF和UDTF動態參數說明

合法@Resolve註解樣本如下。

@Resolve註解樣本

說明

@Resolve('bigint,boolean->string,datetime')

輸入參數類型為BIGINT、BOOLEAN,傳回值類型為STRING、DATETIME。

@Resolve('*->string, datetime')

輸入任意個參數,傳回值類型為STRING、DATETIME。

@Resolve('->double, bigint, string')

無輸入參數,傳回值類型為DOUBLE、BIGINT、STRING。

@Resolve("array<string>,struct<a1:bigint,b1:string>,string->map<string,bigint>,struct<b1:bigint>")

輸入參數類型為ARRAY、STRUCT、MAP,傳回值類型為MAP、STRUCT。

資料類型

在MaxCompute中不同資料類型版本支援的資料類型不同。從MaxCompute 2.0版本開始,擴充了更多的新資料類型,同時還支援ARRAY、MAP、STRUCT等複雜類型。更多MaxCompute資料類型版本資訊,請參見資料類型版本說明

為確保編寫Java UDTF過程中使用的資料類型與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

不涉及

說明

當MaxCompute專案採用MaxCompute 2.0資料類型版本時,UDTF的輸入或傳回值才可以使用Java Writable Type。

使用說明

按照開發流程,完成Java UDTF開發後,您即可通過MaxCompute SQL調用Java UDTF。調用方法如下:

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

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

使用MaxCompute Studio完整開發及調用Java UDTF的操作,請參見使用樣本

使用樣本

以通過MaxCompute Studio開發UDTF為例,開發並調用Java UDTF的操作步驟如下:

  1. 準備工作。

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

    1. 安裝MaxCompute Studio

    2. 建立MaxCompute專案串連

    3. 建立MaxCompute Java Module

  2. 編寫UDTF代碼。

    1. Project地區,按右鍵Module的源碼目錄(即src > main > java),選擇new > MaxCompute Java建立Java Class

    2. Create new MaxCompute java class對話方塊,單擊UDTF並填寫Name後,按Enter鍵。例如Java Class名稱為MyUDTF。選擇類型並填寫名稱

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

    3. 在代碼編寫地區寫入如下代碼。編寫UDTF代碼UDTF程式碼範例如下。

      package org.alidata.odps.udtf.examples;
      import com.aliyun.odps.udf.UDTF;
      import com.aliyun.odps.udf.UDTFCollector;
      import com.aliyun.odps.udf.annotation.Resolve;
      import com.aliyun.odps.udf.UDFException;
      // TODO define input and output types, e.g., "string,string->string,bigint".
         @Resolve("string,bigint->string,bigint")
         public class MyUDTF extends UDTF {
           @Override
           public void process(Object[] args) throws UDFException {
             String a = (String) args[0];
             Long b = (Long) args[1];
             for (String t: a.split("\\s+")) {
               forward(t, b);
             }
           }
         }
  3. 在本地運行調試UDTF,確保代碼可以運行成功。

    更多調試操作,請參見通過本地運行調試UDF

    本地調試UDTF

    說明

    運行參數可參照圖示資料填寫。

  4. 將建立的UDTF打包為JAR包,上傳至MaxCompute專案並註冊函數。例如函數名稱為user_udtf

    更多打包操作,請參見操作步驟

    註冊函數

  5. 在MaxCompute Studio的左側導覽列,單擊Project Explorer,在目標MaxCompute專案上單擊右鍵,啟動MaxCompute用戶端,並執行SQL命令調用新建立的UDTF。

    假設待查詢目標表my_table的資料結構如下。

    +------------+------------+
    | col0       | col1       |
    +------------+------------+
    | A B        | 1          |
    | C D        | 2          |
    +------------+------------+

    執行如下SQL命令調用UDTF。

    select user_udtf(col0, col1) as (c0, c1) from my_table;

    返回結果如下。

    +----+------------+
    | c0 | c1         |
    +----+------------+
    | A  | 1          |
    | B  | 1          |
    | C  | 2          |
    | D  | 2          |
    +----+------------+

相關文檔

關於Java UDTF的使用樣本詳情,請參見Java UDTF使用樣本