本文為您介紹MaxCompute的UDAF和UDTF使用Resolve註解時支援的動態參數文法。
Resolve註解文法擴充
MaxCompute的UDAF和UDTF使用Resolve註解決定函數的Signature,樣本如下。這種方式的局限性在於輸入參數和輸出參數是固定的,無法實現方法重載。
@com.aliyun.odps.udf.annotation.Resolve("BIGINT->DOUBLE")
public class UDTFClass extends UDTF {
...
}
說明 樣本定義了一個UDTF,該UDTF接受的參數類型為BIGINT,傳回值類型為DOUBLE。
現在MaxCompute對Resolve註解文法做了如下擴充:
- 您可以在參數列表中使用
*
,表示接受任意長度、任意類型的輸入參數。例如@Resolve('double,*->String')
表示接受第一個參數是DOUBLE類型,後接任意長度、任意類型的參數列表。此時,您需要自己編寫代碼判斷輸入的個數和參數類型,然後對它們進行相應的操作(您可以對比C語言裡面的printf
函數來理解此操作)。說明 星號用在傳回值列表中時,表示的是不同的含義。 - 您可以在參數列表中使用
any
關鍵字,表示任意類型的參數。例如@Resolve('double,any->string')
表示接受第一個是DOUBLE類型,後接任意類型的參數列表。說明any
不能用在傳回值列表中,也不能用在複雜類型的子類型中(例如ARRAY)。 - UDTF的傳回值可以使用星號,表示返回任意個STRING類型。傳回值的個數與調用函數時設定的別名個數有關。例如
@Resolve("ANY,ANY->DOUBLE,*")
,調用方式是UDTF(x, y) as (a, b, c)
,此處as
後面設定了三個別名,即a、b、c。編輯器會認定a為DOUBLE類型(Annotation中傳回值第一列的類型是給定的),b和c為STRING類型。因為這裡給出了三個傳回值,所以UDTF在調用forward
時,必須forward
長度為3的數組,否則會出現運行時報錯。說明 這種錯誤無法在編譯時間報出,因此UDTF的調用者在SQL中設定alias個數時,必須遵循該UDTF定義的規則。由於彙總函式的傳回值個數固定是1,所以這個功能對UDAF來說並無意義。
UDTF樣本
import com.aliyun.odps.udf.UDFException;
import com.aliyun.odps.udf.UDTF;
import com.aliyun.odps.udf.annotation.Resolve;
import org.json.JSONException;
import org.json.JSONObject;
@Resolve("STRING,*->STRING,*")
public class JsonTuple extends UDTF {
private Object[] result = null;
@Override
public void process(Object[] input) throws UDFException {
if (result == null) {
result = new Object[input.length];
}
try {
JSONObject obj = new JSONObject((String)input[0]);
for (int i = 1; i < input.length; i++) {
// 傳回值要求變長部分都是STRING。
result[i] = String.valueOf(obj.get((String)(input[i])));
}
result[0] = null;
} catch (JSONException ex) {
for (int i = 1; i < result.length; i++) {
result[i] = null;
}
result[0] = ex.getMessage();
}
forward(result);
}
}
以上UDTF樣本中,傳回值個數會根據輸入參數的個數來決定。輸出參數中的第一個參數是一個JSON文本,後面的參數是需要從JSON中解析的Key。傳回值中的第一個傳回值是解析JSON過程中的出錯資訊,如果沒有出錯,則會根據輸入的Key依次輸出從JSON中解析出來的內容。使用樣本如下。 -- 根據輸入參數的個數定製輸出別名個數。
SELECT my_json_tuple(json, 'a', 'b') as exceptions, a, b FROM jsons;
-- 變長部分可以一列都沒有。
SELECT my_json_tuple(json) as exceptions, a, b FROM jsons;
-- 下面這個SQL會出現執行階段錯誤,因為別名個數與實際輸出個數不符。
-- 注意編譯時間無法發現這個錯誤。
SELECT my_json_tuple(json, 'a', 'b') as exceptions, a, b, c FROM jsons;
當本文介紹的這些擴充無法滿足您的業務需求時,建議您使用UDT實現彙總函式和UDTF的功能。詳情請參見UDT概述。
說明 UDAF和UDTF的Python版本樣本請參見Python 3 UDAF和Python 3 UDTF讀取MaxCompute資源樣本。