Todos os produtos
Search
Central de documentação

MaxCompute:UDFs com código incorporado

Última atualização: Aug 20, 2026

Este tópico descreve como usar funções definidas pelo usuário (UDFs) com código incorporado para inserir código Java ou Python diretamente em scripts SQL.

Informações de base

As UDFs com código incorporado do MaxCompute resolvem os seguintes problemas de implementação e manutenção de código:

  • Implementação complexa: após crie UDFs e desenvolver o código, é necessário compilar o código em Java, além de criar resources e funções manualmente.

  • Manutenção difícil: não é possível visualize diretamente a lógica de implementação das UDFs referenciadas em scripts SQL nem obter o source code dos pacotes JAR.

  • Baixa legibilidade do código: para implementar funções de biblioteca Java usando tipos definidos pelo usuário (UDTs), você precisa converter o código Java em expressões dentro de linhas de código extensas. Além disso, alguns trechos de código Java não podem ser escritos como expressões. Exemplo:

    Foo f = new Foo();
    f.execute();
    f.getResult();

Descrição

As UDFs com código incorporado permitem inserir código Java ou Python em scripts SQL. Durante a compilação do script, o Janino-compiler identifica e extrai o código incorporado, compila o código em Java e, em seguida, gera resources dinamicamente e cria funções temporárias.

É possível colocar scripts SQL e linhas de código de terceiros no mesmo arquivo de source code. Isso simplifica o uso de UDTs ou UDFs e facilita o desenvolvimento e a manutenção no dia a dia.

Limites

Apenas o Janino-compiler pode compilar código Java incorporado. A sintaxe do código Java incorporado deve ser um subconjunto da sintaxe padrão do JDK. O código Java incorporado possui as seguintes limitações:

  • Expressões lambda não são suportadas.

  • Não é permitido especifique vários tipos de exceções em um único bloco catch. Por exemplo, catch(Exception1 | Exception2 e) não é permitido.

  • A inferência automática de argumentos genéricos não funciona. Por exemplo, Map map = new HashMap<>(); não é suportado.

  • Expressões para inferência de tipos de argumento são ignoradas. Use expressões de cast para especifique o tipo do argumento, como (String) myMap.get(key).

  • As asserções são forçadamente ativadas, mesmo que a opção -ea da máquina virtual Java (JVM) seja utilizada.

  • Código escrito em versões posteriores ao Java 8 não é suportado.

Referenciar código incorporado em um UDT

O código a seguir fornece um exemplo. Envie as instruções SQL no modo script. Para mais informações, consulte SQL in script mode.

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;
  • #CODE indica o início do bloco de código incorporado. #END CODE indica o fim do bloco de código incorporado. Neste exemplo, o bloco de código incorporado está posicionado ao final do script e se aplica a todo o script.

  • 'lang'='JAVA' indica que o código incorporado está em Java. Substitua JAVA por PYTHON caso esteja compilando código em Python.

  • Use a sintaxe UDT no script SQL para chamar Foo.extractNumber.

Definir e chamar uma UDF Java com código incorporado

O código a seguir fornece um exemplo. Envie as instruções SQL no modo script. Para mais informações, consulte SQL in script mode.

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');
  • O bloco de código incorporado pode ser posicionado após USING ou ao final do script. O bloco de código colocado após USING aplica-se apenas à instrução CREATE TEMPORARY FUNCTION.

  • A função criada por CREATE TEMPORARY FUNCTION é uma função temporária. Essa função temporária tem efeito apenas durante o processo de execução atual e não é armazenada no sistema de metadados do MaxCompute. Para saber como criar uma função permanente e armazená-la no sistema de metadados do MaxCompute, consulte CREATE SQL FUNCTION.

Definir e chamar uma UDTF Java com código incorporado

O código a seguir fornece um exemplo. Envie as instruções SQL no modo script. Para mais informações, consulte SQL in script mode.

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 valor de retorno de @Resolve deve ser do tipo string[]. No entanto, o Janino-compiler não consegue identificar "string->string,string" como string[]. Para resolver esse problema, os parâmetros comentados por @Resolve devem estar entre chaves {}. Ao criar uma UDTF Java pelo método comum, as chaves {} não são obrigatórias.

Definir e chamar uma UDF Python com código incorporado

O código a seguir fornece um exemplo. Envie as instruções SQL no modo script. Para mais informações, consulte SQL in script mode.

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);
  • A indentação do código Python deve obedecer às especificações da linguagem Python.

  • Ao criar uma UDF Python, o nome da classe que segue a cláusula AS deve conter o nome do arquivo do source code Python. Utilize 'filename'='embedded' para especifique um nome de arquivo virtual.

  • Para mais informações sobre o desenvolvimento e o uso de diferentes versões do Python, consulte os seguintes tópicos: