Java言語スカラー関数
次の例は、数値の集合を合計する単純なスカラー関数を示している。 この例では、単純なAEを作るところから始める。 ファイル名は「TestJavaInterface.java。
コード
- Javaインターフェイスに引き込む。 これは通常、以下の方法で実現できる:
import org.netezza.ae.*;
- メインを書く。 使用する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
参照を取得する。 - 関数が使用可能になったら、関数ロジックを呼び出すためのスタブを追加します:
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; } }
- 機能を実装する。関数を実装するには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として返します。
- 最後のコード準備ステップでは、エラーチェックと追加データ型のサポートを追加する。
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
である。
実行中
SELECT applyop_java('+',1,2);
APPLYOP_JAVA
--------------
3
(1 row)
doOnce
で型を検証し、'NzaeException
でエラーを送信していることに注意。 次の例ではエラーが発生する:SELECT applyop_java('-',1,2);
ERROR: invalid operator = -