Função escalar da linguagem Java
Este exemplo usa o seguinte nome de arquivo:
TestJavaInterface.java
Código
O código neste exemplo mostra que, com pequenas alterações, esse programa funciona no modo remoto. A mudança está na parte principal, onde um loop é adicionado ao redor de getAPI para que ele seja chamado duas vezes. Se a conexão for remota, ela será transferida para ser executada por um novo thread e aguardar uma nova conexão. Por fim, se a conexão não for remota, saia do loop após a primeira iteração. Esse código funciona como um AE local e lida com duas iterações como um AE remoto.
import org.netezza.ae.*;
import java.util.concurrent.Executor;
import java.util.concurrent.Executors;
public class TestJavaInterface {
private static final Executor exec =
Executors.newCachedThreadPool();
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();
while (true) {
final NzaeApi api = helper.getApi(NzaeApi.FUNCTION);
if (api.apiType == NzaeApi.FUNCTION) {
if (!helper.isRemote()) {
run(api.aeFunction);
break;
} else {
Runnable task = new Runnable() {
public void run() {
try {
TestJavaInterface.run(api.aeFunction);
} finally {
api.aeFunction.close();
}
}
};
exec.execute(task);
}
}
}
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;
}
}
Compilação
Use a compilação padrão como no modo local:
$NZ_EXPORT_DIR/ae/utilities/bin/compile_ae --language java --template \
compile TestJavaInterface.java --version 3
Registro
O registro é um pouco diferente. Primeiro, execute isso para se registrar:
$NZ_EXPORT_DIR/ae/utilities/bin/register_ae --sig "rem_applyop_java(varargs)" \
--return "double" --class AeUdf --language java --template udf \
--define "java_class=TestJavaInterface" --version 3 --remote \
--rname testjavapi
Isso especifica que o código seja registrado como um ae remoto com um nome remoto de testjavapi, que corresponde ao código. Além disso, um lançador é registrado:
$NZ_EXPORT_DIR/ae/utilities/bin/register_ae --sig "rem_applyop_launch(int8)" \
--return "TABLE(aeresult varchar(255))" --class AeUdtf --language java \
--template udtf --define "java_class=TestJavaInterface" --version 3 \
--remote --rname testjavapi --launch
Com exceção de --rname, --exe e a parte do nome de --sig, todos os inicializadores são parecidos com o acima. Nesse caso, é um UDTF, pois essa é a interface de todos os lançadores. O valor de --rname deve corresponder ao nome no código.
Executando
Para executar o AE no modo remoto, o executável é executado como um "servidor" Nesse caso, ele lida apenas com as consultas executadas no host. Normalmente, os AEs também são iniciados nas SPUs. Iniciar uma instância no host:
SELECT * FROM TABLE WITH FINAL(rem_applyop_launch(0));
AERESULT
-------------------------------------------------------------------------
tran: 14896 session: 18286 DATA slc: 0 hardware: 0 machine: bdrosendev process:
15937 thread: 15938
(1 row)
Observe que uma sintaxe diferente é usada para invocar o iniciador de estilo de função de tabela. Essa é a sintaxe usada para chamar qualquer AE baseado em UDTF. Agora, execute o AE:
SELECT rem_applyop_java('+', 4,5,1.1);
REM_APPLYOP_JAVA
------------------
10.1
(1 row)
Por fim, cause um erro:
SELECT rem_applyop_java(1);
ERROR: first input column expected to be a string type