As UDFs com código incorporado permitem definir lógica Java ou Python diretamente em um script SQL, eliminando o fluxo separado de compilação, upload e registro das UDFs padrão. Como as instruções SQL e o código da função residem no mesmo arquivo, a lógica torna-se imediatamente visível e mais fácil de manter.
Envie todos os exemplos desta página em modo script.
Quando usar UDFs com código incorporado
Use UDFs com código incorporado quando:
A função for usada apenas no script atual e não precisar de reutilização em vários jobs SQL.
Desejar manter a implementação e a consulta juntas em um único arquivo para melhorar a legibilidade.
Estiver criando protótipos ou iterando rapidamente e quiser pular a etapa de empacotamento JAR.
Prefira uma UDF padrão quando:
Vários scripts SQL compartilharem a mesma lógica de função.
O código Java depender de recursos incompatíveis com o compilador Janino (consulte Limitações).
A base de código for muito grande para incorporação inline.
Como funciona
Ao compilar um script com um bloco de código incorporado, o MaxCompute usa o compilador Janino para identificar e extrair esse código, compilá-lo, gerar recursos dinamicamente e criar uma função temporária. Essa função temporária não é armazenada como entrada persistente no sistema de metadados do MaxCompute.
Referência rápida de sintaxe
|
Parâmetro |
Valores |
Descrição |
|
|
|
Linguagem do código incorporado |
|
|
Qualquer string |
Nome de arquivo virtual. Obrigatório para UDFs Python (usado na cláusula |
Sintaxe do bloco de código incorporado:
#CODE ('lang'='JAVA')
<your Java or Python code>
#END CODE;
Posicionamento do bloco de código:
|
Posicionamento |
Escopo |
|
Após |
Aplica-se apenas a essa instrução |
|
No final do script |
Aplica-se a todo o script |
Limitações
O compilador Janino compila o código Java incorporado e suporta apenas um subconjunto da sintaxe padrão do JDK. Os seguintes recursos não estão disponíveis:
|
Limitação |
Solução alternativa |
|
|
Expressões lambda não são suportadas. |
— |
|
|
Múltiplos tipos de exceção em um único bloco |
Exception2 e)` não é permitido. |
— |
|
Inferência de argumentos genéricos não é suportada. |
Especifique o tipo explicitamente: |
|
|
Expressões para inferência de argumentos de tipo são ignoradas. |
Use expressões de cast: |
|
|
Assertions estão sempre ativadas, independentemente da definição da opção JVM |
— |
|
|
Versões do Java posteriores ao Java 8 não são suportadas. |
— |
Referenciar código incorporado em um tipo definido pelo usuário (UDT)
Coloque o bloco de código incorporado no final do script. Ele se aplicará a todo o script.
SELECT
s,
com.mypackage.Foo.extractNumber(s)
FROM VALUES ('abc123def'), ('apple') AS t(s);
#CODE ('lang'='JAVA')
package com.mypackage;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class Foo {
final static Pattern compile = Pattern.compile(".*?([0-9]+).*");
public static String extractNumber(String input) {
final Matcher m = compile.matcher(input);
if (m.find()) {
return m.group(1);
}
return null;
}
}
#END CODE;
Chame a classe incorporada usando seu nome totalmente qualificado (com.mypackage.Foo.extractNumber) diretamente na consulta SQL.
Definir e chamar uma UDF Java
Posicione o bloco de código incorporado imediatamente após USING para restringir seu escopo à instrução CREATE TEMPORARY FUNCTION ou no final do script.
CREATE TEMPORARY FUNCTION foo AS 'com.mypackage.Reverse' USING
#CODE ('lang'='JAVA')
package com.mypackage;
import com.aliyun.odps.udf.UDF;
public class Reverse extends UDF {
public String evaluate(String input) {
if (input == null) return null;
StringBuilder ret = new StringBuilder();
for (int i = input.toCharArray().length - 1; i >= 0; i--) {
ret.append(input.toCharArray()[i]);
}
return ret.toString();
}
}
#END CODE;
SELECT foo('abdc');
CREATE TEMPORARY FUNCTION cria uma função temporária válida apenas para a execução atual. Ela não é armazenada no sistema de metadados do MaxCompute. Para criar uma função permanente, consulte CREATE SQL FUNCTION.
Definir e chamar uma função de valor de tabela definida pelo usuário (UDTF) Java
CREATE TEMPORARY FUNCTION foo AS 'com.mypackage.Reverse' USING
#CODE ('lang'='JAVA', 'filename'='embedded.jar')
package com.mypackage;
import com.aliyun.odps.udf.UDTF;
import com.aliyun.odps.udf.UDFException;
import com.aliyun.odps.udf.annotation.Resolve;
@Resolve({"string->string,string"})
public class Reverse extends UDTF {
@Override
public void process(Object[] objects) throws UDFException {
String str = (String) objects[0];
String[] split = str.split(",");
forward(split[0], split[1]);
}
}
#END CODE;
SELECT foo('ab,dc') AS (a,b);
O compilador Janino não reconhece"string->string,string"como tipostring[]. Coloque os parâmetros de@Resolveentre chaves{}— por exemplo,@Resolve({"string->string,string"}). Essa solução alternativa é necessária apenas para UDTFs com código incorporado; UDTFs padrão não exigem as chaves.
Definir e chamar uma UDF Python
CREATE TEMPORARY FUNCTION foo AS 'embedded.UDFTest' USING
#CODE ('lang'='PYTHON', 'filename'='embedded')
from odps.udf import annotate
@annotate("bigint->bigint")
class UDFTest(object):
def evaluate(self, a):
return a * a
#END CODE;
SELECT foo(4);
Dois detalhes são específicos para UDFs Python:
Nome de arquivo virtual: O nome da classe na cláusula
ASdeve incluir o nome do arquivo source Python. Use'filename'='embedded'para especificar esse nome de arquivo virtual.Indentação: O código Python dentro do bloco incorporado deve seguir as regras padrão de indentação do Python.
Para guias de desenvolvimento específicos por versão do Python, consulte Desenvolver uma UDF em Python 2 e Desenvolver uma UDF em Python 3.