UDAF和UDTF動(dòng)態(tài)參數(shù)說明
本文為您介紹MaxCompute的UDAF和UDTF使用Resolve注解時(shí)支持的動(dòng)態(tài)參數(shù)語(yǔ)法。
Resolve注解語(yǔ)法擴(kuò)展
MaxCompute的UDAF和UDTF使用Resolve注解決定函數(shù)的Signature,示例如下。這種方式的局限性在于輸入?yún)?shù)和輸出參數(shù)是固定的,無法實(shí)現(xiàn)方法重載。
@com.aliyun.odps.udf.annotation.Resolve("BIGINT->DOUBLE")
public class UDTFClass extends UDTF {
...
}
示例定義了一個(gè)UDTF,該UDTF接受的參數(shù)類型為BIGINT,返回值類型為DOUBLE。
現(xiàn)在MaxCompute對(duì)Resolve注解語(yǔ)法做了如下擴(kuò)展:
您可以在參數(shù)列表中使用
*
,表示接受任意長(zhǎng)度、任意類型的輸入?yún)?shù)。例如@Resolve('double,*->String')
表示接受第一個(gè)參數(shù)是DOUBLE類型,后接任意長(zhǎng)度、任意類型的參數(shù)列表。此時(shí),您需要自己編寫代碼判斷輸入的個(gè)數(shù)和參數(shù)類型,然后對(duì)它們進(jìn)行相應(yīng)的操作(您可以對(duì)比C語(yǔ)言里面的printf
函數(shù)來理解此操作)。說明星號(hào)用在返回值列表中時(shí),表示的是不同的含義。
您可以在參數(shù)列表中使用
any
關(guān)鍵字,表示任意類型的參數(shù)。例如@Resolve('double,any->string')
表示接受第一個(gè)是DOUBLE類型,后接任意類型的參數(shù)列表。說明any
不能用在返回值列表中,也不能用在復(fù)雜類型的子類型中(例如ARRAY)。UDTF的返回值可以使用星號(hào),表示返回任意個(gè)STRING類型。返回值的個(gè)數(shù)與調(diào)用函數(shù)時(shí)設(shè)置的別名個(gè)數(shù)有關(guān)。例如
@Resolve("ANY,ANY->DOUBLE,*")
,調(diào)用方式是UDTF(x, y) as (a, b, c)
,此處as
后面設(shè)置了三個(gè)別名,即a、b、c。編輯器會(huì)認(rèn)定a為DOUBLE類型(Annotation中返回值第一列的類型是給定的),b和c為STRING類型。因?yàn)檫@里給出了三個(gè)返回值,所以UDTF在調(diào)用forward
時(shí),必須forward
長(zhǎng)度為3的數(shù)組,否則會(huì)出現(xiàn)運(yùn)行時(shí)報(bào)錯(cuò)。說明這種錯(cuò)誤無法在編譯時(shí)報(bào)出,因此UDTF的調(diào)用者在SQL中設(shè)置alias個(gè)數(shù)時(shí),必須遵循該UDTF定義的規(guī)則。由于聚合函數(shù)的返回值個(gè)數(shù)固定是1,所以這個(gè)功能對(duì)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++) {
// 返回值要求變長(zhǎng)部分都是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示例中,返回值個(gè)數(shù)會(huì)根據(jù)輸入?yún)?shù)的個(gè)數(shù)來決定。輸出參數(shù)中的第一個(gè)參數(shù)是一個(gè)JSON文本,后面的參數(shù)是需要從JSON中解析的Key。返回值中的第一個(gè)返回值是解析JSON過程中的出錯(cuò)信息,如果沒有出錯(cuò),則會(huì)根據(jù)輸入的Key依次輸出從JSON中解析出來的內(nèi)容。使用示例如下。
-- 根據(jù)輸入?yún)?shù)的個(gè)數(shù)定制輸出別名個(gè)數(shù)。
SELECT my_json_tuple(json, 'a', 'b') as exceptions, a, b FROM jsons;
-- 變長(zhǎng)部分可以一列都沒有。
SELECT my_json_tuple(json) as exceptions, a, b FROM jsons;
-- 下面這個(gè)SQL會(huì)出現(xiàn)運(yùn)行時(shí)錯(cuò)誤,因?yàn)閯e名個(gè)數(shù)與實(shí)際輸出個(gè)數(shù)不符。
-- 注意編譯時(shí)無法發(fā)現(xiàn)這個(gè)錯(cuò)誤。
SELECT my_json_tuple(json, 'a', 'b') as exceptions, a, b, c FROM jsons;
當(dāng)本文介紹的這些擴(kuò)展無法滿足您的業(yè)務(wù)需求時(shí),建議您使用UDT實(shí)現(xiàn)聚合函數(shù)和UDTF的功能。詳情請(qǐng)參見UDT概述。
UDAF和UDTF的Python版本示例請(qǐng)參見Python 3 UDAF和Python 3 UDTF讀取MaxCompute資源示例。