Java言語スカラー関数

次の例は、数値の集合を合計する単純なスカラー関数を示している。 この例では、単純なAEを作るところから始める。 ファイル名は「TestJavaInterface.java

コード

  1. Javaインターフェイスに引き込む。 これは通常、以下の方法で実現できる:
    import org.netezza.ae.*;
  2. メインを書く。 使用するAPI(この場合は関数)を決定する。 ローカルまたはリモートのAE接続を取得する。 この例では、ローカルAE接続を使用している。 接続を得るために使用できるインターフェースは2つある。 ひとつは「NzaeFactory使ったもので、もうひとつは「NzaeApiGenerator使ったものだ。 この例では、ジェネレーター・クラスを使用しています。ジェネレーター・クラスはシンプルで、リモート・モードにも使用できます。 プログラムは次のように表示されるはずだ:
    import org.netezza.ae.*;
    public class TestJavaInterface {
    public static final void main(String [] args) {
    try {
    mainImpl(args);
    } catch (Throwable t) {
    System.err.println(t.toString());
    NzaeUtil.logException(t, "main");
    }
    }
    public static final void mainImpl(String [] args) {
    NzaeApiGenerator helper = new NzaeApiGenerator();
    final NzaeApi api = helper.getApi(NzaeApi.FUNCTION);
    helper.close();
    }
    }

    これは、使用可能な'NzaeFunctionオブジェクトを含む'NzaeApi参照を取得する。

  3. 関数が使用可能になったら、関数ロジックを呼び出すためのスタブを追加します:
    import org.netezza.ae.*;
    public class TestJavaInterface {
    public static final void main(String [] args) {
    try {
    mainImpl(args);
    } catch (Throwable t) {
    System.err.println(t.toString());
    NzaeUtil.logException(t, "main");
    }
    }
    public static final void mainImpl(String [] args) {
    NzaeApiGenerator helper = new NzaeApiGenerator();
    final NzaeApi api = helper.getApi(NzaeApi.FUNCTION);
    run(api.aeFunction);
    helper.close();
    }
    public static int run(Nzae aeFunc)
    {
    return 0;
    }
    }
  4. 機能を実装する。
    関数を実装するには2つの方法がある。 ひとつは、「Nzaeオブジェクト・インターフェースを直接使う方法だ。 もうひとつは、よりシンプルなインターフェイスを提供する「NzaeMessageHandler由来のクラスを実装することだ。 この例では、メッセージ・ハンドラを使う。 つ目の方法は、別の例で説明する。 メッセージ・ハンドラは、入力1行につき出力1行を返す関数にのみ使用できる。 また、ハンドラーはいくつかのエラー処理の詳細を自動的にカバーする。
    import org.netezza.ae.*;
    public class TestJavaInterface {
    public static final void main(String [] args) {
    try {
    mainImpl(args);
    } catch (Throwable t) {
    System.err.println(t.toString());
    NzaeUtil.logException(t, "main");
    }
    }
    public static final void mainImpl(String [] args) {
    NzaeApiGenerator helper = new NzaeApiGenerator();
    final NzaeApi api = helper.getApi(NzaeApi.FUNCTION);
    run(api.aeFunction);
    helper.close();
    }
    public static class MyHandler implements NzaeMessageHandler
    {
    public void evaluate(Nzae ae, NzaeRecord input, NzaeRecord output) {
    final NzaeMetadata meta = ae.getMetadata();
    int op = 0;
    double result = 0;
    for (int i = 0; i < input.size(); i++) {
    if (input.getField(i) == null) {
    continue;
    }
    int dataType = meta.getInputNzType(i);
    if (i == 0) {
    if (!(dataType == NzaeDataTypes.NZUDSUDX_FIXED
    || dataType == NzaeDataTypes.NZUDSUDX_VARIABLE)) {
    ae.userError("first column must be a string");
    }
    String opStr = input.getFieldAsString(0);
    if (opStr.equals("*")) {
    result = 1;
    op = OP_MULT;
    }
    else if (opStr.equals("+")) {
    result = 0;
    op = OP_ADD;
    }
    else {
    ae.userError("invalid operator = " + opStr);
    }
    continue;
    }
    switch (dataType) {
    case NzaeDataTypes.NZUDSUDX_INT32:
    switch (op) {
    case OP_ADD:
    result +=
    input.getFieldAsNumber(i).doubleValue();
    break;
    case OP_MULT:
    result *=
    input.getFieldAsNumber(i).doubleValue();
    break;
    default:
    break;
    }
    break;
    default:
    break;
    }
    } // end of column for loop
    output.setField(0, result);
    }
    }
    private static final int OP_ADD = 1;
    private static final int OP_MULT = 2;
    public static int run(Nzae ae)
    {
    ae.run(new MyHandler());
    return 0;
    }
    }

    この例では、run関数はハンドラーオブジェクトをインスタンス化し、関数クラスのrunメソッドをハンドラー上で呼び出している。 ハンドラーはevaluateメソッドを実装しなければならない。evaluateメソッドは関数への参照と、入力レコードと出力レコードへの参照を取る。 通常の関数では、出力レコードの列は1つだけである。 evaluateは入力レコードからフィールドを取得し、それを使って出力フィールドを設定することができる。 このコードは、最初の引数に文字列プラス記号(+)または文字列アスタリスク(*)を取り、それ以降の引数にINT32値を取る、エラーチェックのない基本的な関数を提供する。 そして、指定された引数値に基づいてINT32値を加算または乗算し、その結果をdoubleとして返します。

  5. 最後のコード準備ステップでは、エラーチェックと追加データ型のサポートを追加する。
    import org.netezza.ae.*;
    public class TestJavaInterface {
    public static final void main(String [] args) {
    try {
    mainImpl(args);
    } catch (Throwable t) {
    System.err.println(t.toString());
    NzaeUtil.logException(t, "main");
    }
    }
    public static final void mainImpl(String [] args) {
    NzaeApiGenerator helper = new NzaeApiGenerator();
    final NzaeApi api = helper.getApi(NzaeApi.FUNCTION);
    run(api.aeFunction);
    helper.close();
    }
    public static class MyHandler implements NzaeMessageHandler
    {
    public void evaluate(Nzae ae, NzaeRecord input, NzaeRecord output) {
    final NzaeMetadata meta = ae.getMetadata();
    int op = 0;
    double result = 0;
    if (meta.getOutputColumnCount() != 1 ||
    meta.getOutputNzType(0) != NzaeDataTypes.NZUDSUDX_DOUBLE) {
    throw new NzaeException("expecting one output column of type "+
    "double");
    }
    if (meta.getInputColumnCount() < 1) {
    throw new NzaeException("expecting at least one input column");
    }
    if (meta.getInputNzType(0) != NzaeDataTypes.NZUDSUDX_FIXED &&
    meta.getInputNzType(0) != NzaeDataTypes.NZUDSUDX_VARIABLE) {
    throw new NzaeException("first input column expected to be "+
    "a string type");
    }
    for (int i = 0; i < input.size(); i++) {
    if (input.getField(i) == null) {
    continue;
    }
    int dataType = meta.getInputNzType(i);
    if (i == 0) {
    if (!(dataType == NzaeDataTypes.NZUDSUDX_FIXED
    || dataType == NzaeDataTypes.NZUDSUDX_VARIABLE)) {
    ae.userError("first column must be a string");
    }
    String opStr = input.getFieldAsString(0);
    if (opStr.equals("*")) {
    result = 1;
    op = OP_MULT;
    }
    else if (opStr.equals("+")) {
    result = 0;
    op = OP_ADD;
    }
    else {
    ae.userError("invalid operator = " + opStr);
    }
    continue;
    }
    switch (dataType) {
    case NzaeDataTypes.NZUDSUDX_INT8:
    case NzaeDataTypes.NZUDSUDX_INT16:
    case NzaeDataTypes.NZUDSUDX_INT32:
    case NzaeDataTypes.NZUDSUDX_INT64:
    case NzaeDataTypes.NZUDSUDX_FLOAT:
    case NzaeDataTypes.NZUDSUDX_DOUBLE:
    case NzaeDataTypes.NZUDSUDX_NUMERIC32:
    case NzaeDataTypes.NZUDSUDX_NUMERIC64:
    case NzaeDataTypes.NZUDSUDX_NUMERIC128:
    switch (op) {
    case OP_ADD:
    result +=
    input.getFieldAsNumber(i).doubleValue();
    break;
    case OP_MULT:
    result *=
    input.getFieldAsNumber(i).doubleValue();
    break;
    default:
    break;
    }
    break;
    default:
    break;
    }
    } // end of column for loop
    output.setField(0, result);
    }
    }
    private static final int OP_ADD = 1;
    private static final int OP_MULT = 2;
    public static int run(Nzae ae)
    {
    ae.run(new MyHandler());
    return 0;
    }
    }

    このコードは、入力引数の数と種類、出力引数の数と種類が正しいことを保証する。 float、double、numericのすべての整数型をサポートしている。 コードが完成したら、コンパイルして登録しなければならない。

コンパイル

コンパイルするには、次のようにする:
$NZ_EXPORT_DIR/ae/utilities/bin/compile_ae --language java --template \
compile TestJavaInterface.java --version 3

引数には、Java言語、バージョン3、テンプレート・コンパイル、ソース・ファイル'TestJavaInterface.javaからの'TestJavaInterface.classファイルの作成を指定する。

登録

コンパイルされると、コードは次のように登録される:
$NZ_EXPORT_DIR/ae/utilities/bin/register_ae --sig "applyop_java(varargs)" \
--return "double" --class AeUdf --language java --template udf \
--define "java_class=TestJavaInterface" --version 3

これはUDFを'applyop_javaとして登録し、様々な引数を取り、doubleを返す。 クラスは'AeUdfで、テンプレートはudfである。 これはデータベースdbに登録され、実行されるJavaクラスは'TestJavaInterfaceである。

実行中

これでAEをSQLで実行できるようになった:
SELECT applyop_java('+',1,2);
APPLYOP_JAVA
--------------
3
(1 row)
コードでは、'doOnceで型を検証し、'NzaeExceptionでエラーを送信していることに注意。 次の例ではエラーが発生する:
SELECT applyop_java('-',1,2);
ERROR: invalid operator = -