このトピックでは、MaxCompute の UDAF および UDTF で Resolve アノテーションを使用して動的パラメーターを扱う方法について説明します。
Resolve アノテーションの拡張構文
MaxCompute では、UDAF および UDTF は Resolve アノテーションを使用して関数のシグネチャを決定します。
@com.aliyun.odps.udf.annotation.Resolve("BIGINT->DOUBLE")
public class UDTFClass extends UDTF {
...
}
この例では、BIGINT 型の入力パラメーターを受け取り、DOUBLE 型の値を返す UDTF を定義しています。
MaxCompute は、Resolve アノテーション構文で以下の拡張機能をサポートしています。
-
入力パラメーターリストで
*を使用すると、任意の型の可変個の入力パラメーターを受け取ることができます。たとえば、@Resolve('double,*->String')は、関数が最初の入力パラメーターとして DOUBLE を受け取り、その後に任意の型と数のパラメーターが続くことを示します。その後、入力パラメーターの数と型をチェックし、それに応じて処理するコードを記述する必要があります。このメカニズムは、C 言語のprintf関数に類似しています。説明アスタリスクは戻り値リストでは異なる意味を持ちます。
-
入力パラメーターリストで
anyキーワードを使用して、任意の型のパラメーターを表すことができます。たとえば、@Resolve('double,any->string')は、関数が DOUBLE 型の最初の入力パラメーターと任意の型の 2 番目の入力パラメーターを受け取ることを示します。説明anyキーワードは、戻り値リストや ARRAY などの複合型のサブタイプには使用できません。 -
UDTF の戻り値は、任意の数の STRING 型の値を表すアスタリスク (*) にすることができます。戻り値の数は、関数の呼び出し時に指定されるエイリアスの数によって決まります。たとえば、アノテーション
@Resolve("ANY,ANY->DOUBLE,*")を使用する場合、関数はUDTF(x, y) as (a, b, c)のように呼び出されます。この場合、asの後に a、b、c の 3 つのエイリアスが指定されています。エディタは、aがアノテーションで最初の戻り値として指定されている DOUBLE 型であり、bとcが STRING 型であると判断します。3 つの戻り値が指定されているため、UDTF はforwardメソッドが呼び出されたときに、長さ 3 の配列をforwardする必要があります。そうでない場合、ランタイムエラーが発生します。説明この種のエラーはコンパイル時には検出できません。そのため、UDTF を呼び出すときは、SQL クエリ内のエイリアスの数が UDTF によって返される列の数と一致する必要があります。この機能は UDAF には適用されません。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 オブジェクトから抽出するキーです。最初の戻り値は解析エラーを報告します。解析が成功した場合、この値は null になり、後続の値は各キーに対して抽出されたコンテンツになります。この UDTF の使用例は次のとおりです。
-- 入力パラメーターの数に基づいて出力エイリアスの数をカスタマイズします。
SELECT my_json_tuple(json, 'a', 'b') as exceptions, a, b FROM jsons;
-- 解析するJSONフィールドがない場合は、エラーメッセージ列のみが返されます。
SELECT my_json_tuple(json) as exceptions FROM jsons;
-- 次のSQLステートメントは、エイリアスの数が実際の出力数と一致しないため、
-- 実行時エラーが発生します。
-- このエラーはコンパイル時には検出できないことに注意してください。
SELECT my_json_tuple(json, 'a', 'b') as exceptions, a, b, c FROM jsons;
このトピックで説明した拡張機能がビジネス要件を満たさない場合は、UDT を使用して同様の機能を実装できます。詳細については、「UDT 概要」をご参照ください。
UDAF および UDTF の Python の例については、「Python 3 UDAF」および「MaxCompute リソースを読み取る Python 3 UDTF の例」をご参照ください。