Se as funções integradas do MaxCompute não atenderem às suas necessidades, use o fluxo de trabalho descrito neste tópico para criar uma função definida pelo usuário (UDF) em ferramentas de desenvolvimento como IntelliJ IDEA (Maven) ou MaxCompute Studio. Em seguida, chame a UDF no MaxCompute para dar suporte a diversos casos de uso. Este tópico descreve como escrever uma UDF em Java.
Limites rígidos
Acesso à Internet — Por padrão, as UDFs não têm acesso à Internet. Para ative esse acesso, envie uma solicitação de conexão de rede. Após a aprovação, a equipe de suporte técnico do MaxCompute entrará em contato para estabelecer a conexão. Para mais detalhes, consulte Network Connection Request FormProcesso de conexão de rede.
Acesso à VPC — As UDFs não acessam recursos em uma virtual private cloud (VPC) por padrão. Para permitir o acesso à VPC, estabeleça uma conexão de rede entre o MaxCompute e a VPC. Para mais detalhes, consulte Usar UDFs para acessar recursos em VPCs.
Tipos de tabela não suportados — UDFs, UDAFs e UDTFs não leem dados dos seguintes tipos de tabela:
Tabelas com evolução de schema
Tabelas com tipos de dados complexos
Tabelas com tipos de dados JSON
Tabelas transacionais
Observações de uso
Antes de escrever uma UDF em Java, compreenda a estrutura do código da UDF e os mapeamentos entre os tipos de dados da UDF Java e os do MaxCompute. Para obter mais informações sobre esses mapeamentos, consulte Apêndice: Tipos de dados.
Ao desenvolver sua UDF em Java, observe os pontos abaixo:
Evite incluir classes com o mesmo nome, mas lógicas diferentes, em arquivos JAR de UDF distintos. Por exemplo, suponha que UDF1 e UDF2 correspondam aos arquivos de recurso udf1.jar e udf2.jar, e ambos contenham uma classe chamada
com.aliyun.UserFunction.class, porém com implementações diferentes. Se você chamar UDF1 e UDF2 na mesma instrução SQL, o MaxCompute carregará aleatoriamente uma das classes. Isso pode gerar resultados de execução inesperados ou até falhas de compilação.Em uma UDF Java, os tipos de dados dos parâmetros de entrada e dos valores de retorno devem ser tipos de objeto (por exemplo, String, Long), e não tipos primitivos (como int, long).
Valores NULL no SQL são mapeados como NULL em Java. Tipos primitivos do Java não representam valores NULL do SQL e, portanto, não são permitidos.
Fluxo de trabalho de desenvolvimento de UDF
O desenvolvimento de uma UDF envolve várias etapas: preparação do ambiente, escrita do código, upload do arquivo JAR, registro da função e depuração. As seções a seguir demonstram esse fluxo usando MaxCompute Studio, DataWorks e odpscmd.
Uso do MaxCompute Studio
O exemplo a seguir mostra como desenvolver e chamar uma UDF em Java que converte caracteres para minúsculas no MaxCompute Studio.
-
Prepare o ambiente.
Para desenvolver e depurar uma UDF no MaxCompute Studio, instale o MaxCompute Studio e conecte-o a um projeto do MaxCompute. Para mais informações, consulte os tópicos a seguir:
-
Escreva o código da UDF.
No explorador Project, clique em com o botão direito no diretório de source code do módulo () e selecione .

-
Na caixa de diálogo Create new MaxCompute java class, clique em UDF, insira o nome da classe no campo Name e pressione Enter.

O campo Name define o nome da MaxCompute Java Class a ser criada. Caso ainda não tenha criado um pacote, insira packagename.classname para criá-lo automaticamente. Neste exemplo, a Java Class recebe o nome Lower.
-
Desenvolva o código da UDF no editor.
Exemplo:package com.aliyun.odps.udf.example; import com.aliyun.odps.udf.UDF; public final class Lower extends UDF { public String evaluate(String s) { if (s == null) { return null; } return s.toLowerCase(); } }NotaPara depurar a UDF Java localmente, consulte Desenvolver e depurar UDFs.
-
Faça o upload e registre a UDF.
Clique em com o botão direito no arquivo Java da UDF e selecione Deploy to server.... Na caixa de diálogo Package a jar, submit resource and register function, configure os parâmetros e clique em OK.

MaxCompute project: Nome do projeto do MaxCompute ao qual a UDF pertence. Como a UDF foi escrita no projeto conectado, mantenha o valor padrão.
Resource file: Caminho do arquivo de recurso do qual a UDF depende. Mantenha o valor padrão.
Resource name: Recurso necessário para a UDF. Mantenha o valor padrão.
Function name: Nome usado para chamar a UDF nas instruções SQL. Exemplo: Lower_test.
-
Depure a UDF.
No painel de navegação à esquerda, clique em Project Explore. Clique em com o botão direito no projeto do MaxCompute desejado e selecione Open Console. No console, insira a instrução SQL que chama a UDF e pressione Enter para executá-la.
Exemplo:select lower_test('ABC');O resultado retornado será semelhante ao seguinte:
+-----+ | _c0 | +-----+ | abc | +-----+
Uso do DataWorks
-
Prepare o ambiente.
Para desenvolver e depurar uma UDF no DataWorks, ative o serviço e vincule um projeto do MaxCompute a ele. Para mais informações, consulte Usar o DataWorks.
-
Escreva o código da UDF.
Use qualquer ferramenta de desenvolvimento Java para escrever o código e empacotá-lo em um arquivo JAR. Exemplo:
package com.aliyun.odps.udf.example; import com.aliyun.odps.udf.UDF; public final class Lower extends UDF { public String evaluate(String s) { if (s == null) { return null; } return s.toLowerCase(); } } -
Faça o upload e registre a UDF.
Envie o código empacotado para o DataWorks e registre a função. Para mais detalhes, veja os tópicos abaixo:
-
Depure a UDF.
Após registrar a UDF, crie um nó ODPS SQL e execute um comando SQL nesse nó para depurá-la. Para saber como criar um nó ODPS SQL, consulte Criar um nó ODPS SQL. Abaixo está um exemplo de comando de depuração.
select lower_test('ABC');
Uso do odpscmd
-
Prepare o ambiente.
Para desenvolver e depurar uma UDF com o odpscmd, instale o cliente e configure sua conexão com um projeto do MaxCompute. Para mais informações, consulte Usar o cliente do MaxCompute (odpscmd).
-
Escreva o código da UDF.
Use qualquer ferramenta de desenvolvimento Java para escrever o código e empacotá-lo em um arquivo JAR. Exemplo:
package com.aliyun.odps.udf.example; import com.aliyun.odps.udf.UDF; public final class Lower extends UDF { public String evaluate(String s) { if (s == null) { return null; } return s.toLowerCase(); } } -
Faça o upload e registre a UDF.
Use o odpscmd para enviar o código empacotado e registrar a função. Consulte os tópicos a seguir para mais detalhes:
-
Depure a UDF.
Depois de registrar a UDF, escreva e execute um comando SQL para testá-la. Veja abaixo um exemplo de comando de depuração.
select lower_test('ABC');
Chamada de UDFs
Após desenvolver uma UDF em Java conforme descrito no Fluxo de trabalho de desenvolvimento de UDF anterior, chame-a no MaxCompute SQL. Os métodos disponíveis são:
Dentro de um projeto — Chame a UDF diretamente, assim como qualquer função integrada.
-
Entre projetos — Para usar uma UDF do projeto B dentro do projeto A, referencie-a com o prefixo do projeto:
select B:udf_in_other_project(arg0, arg1) as res from table_t;Para configurar o compartilhamento entre projetos, consulte Acesso a recursos entre projetos baseado em pacotes.
Exemplos de UDF
Apêndice: Estrutura do código da UDF
Uma UDF em Java é composta pelas seguintes partes:
-
Pacote Java: Opcional.
Agrupe suas classes Java em um pacote para facilitar a localização e a reutilização.
-
Herança da classe UDF: Obrigatória.
A classe base necessária é
com.aliyun.odps.udf.UDF. Se precisar de outras classes de UDF ou tipos de dados complexos, adicione as classes correspondentes do SDK do MaxCompute. Por exemplo, a classe para o tipo de dados STRUCT écom.aliyun.odps.data.Struct. -
Anotação
@Resolve: Opcional.O formato é
@Resolve(<signature>), ondesignaturedefine os tipos de dados dos parâmetros de entrada e do valor de retorno. Ao usar o tipo STRUCT em uma UDF, a reflexão não recupera nomes e tipos de campos decom.aliyun.odps.data.Struct. Nesse cenário, use a anotação@Resolvepara obtê-los. Se a UDF usar STRUCT, adicione a anotação@Resolveà classe da UDF. Essa anotação afeta apenas as sobrecargas cujos parâmetros ou valores de retorno contenham com.aliyun.odps.data.Struct. Exemplo:@Resolve("struct<a:string>,string->string"). Para um exemplo detalhado, consulte Exemplo de UDF: Tipos de Dados Complexos. -
Classe Java personalizada: Obrigatória.
Representa a unidade que organiza o código da UDF, definindo variáveis e métodos que implementam a lógica de negócio.
-
Método
evaluate: Obrigatório.Sua classe Java personalizada deve incluir um método
evaluatepúblico e não estático. Os tipos de dados de seus parâmetros de entrada e valor de retorno definem a assinatura SQL da UDF.É possível implementar múltiplos métodos
evaluate. Durante a chamada da UDF, o MaxCompute seleciona o métodoevaluatecorreto com base nos tipos dos argumentos.Ao escrever uma UDF em Java, use tipos Java ou tipos Java Writable. Para ver os mapeamentos detalhados entre tipos de dados do MaxCompute e Java, consulte Apêndice: Tipos de dados.
Inicialização e limpeza da UDF: Opcional. Implemente essas rotinas usando
void setup(ExecutionContext ctx)evoid close(). O métodovoid setup(ExecutionContext ctx)é chamado uma única vez antes do métodoevaluatee serve para inicializar recursos ou objetos membros necessários à computação. Já o métodovoid close()é executado uma vez após todas as chamadas aoevaluateserem concluídas e serve para tarefas de limpeza, como fechar arquivos.
Os exemplos abaixo ilustram dois tipos de UDFs.
-
Uso de tipos Java
// Organize the Java class in the org.alidata.odps.udf.examples package. package org.alidata.odps.udf.examples; // Inherit the UDF class. import com.aliyun.odps.udf.UDF; // Define a custom Java class. public final class Lower extends UDF { // The evaluate method defines the UDF's logic. It takes a String and returns a String. public String evaluate(String s) { if (s == null) { return null; } return s.toLowerCase(); } } -
Uso de tipos Java Writable
// Organize the Java class in the com.aliyun.odps.udf.example package. package com.aliyun.odps.udf.example; // Add the required classes for the Java Writable type. import com.aliyun.odps.io.Text; // Inherit the UDF class. import com.aliyun.odps.udf.UDF; // Define a custom Java class. public class MyConcat extends UDF { private Text ret = new Text(); // Define the evaluate method. `Text` specifies the data type of the input parameters, and the `return` value is also a Text object. public Text evaluate(Text a, Text b) { if (a == null || b == null) { return null; } ret.clear(); ret.append(a.getBytes(), 0, a.getLength()); ret.append(b.getBytes(), 0, b.getLength()); return ret; } }
O MaxCompute também suporta UDFs desenvolvidas para sua versão compatível com Hive. Para mais informações, consulte Compatibilidade com UDFs do Hive.
Apêndice: Tipos de dados
Mapeamentos de tipos de dados
Para garantir consistência entre os tipos usados em uma UDF Java e aqueles suportados pelo MaxCompute, use os mapeamentos a seguir.
Os tipos de dados suportados variam conforme a edição de tipos de dados do MaxCompute. A partir da versão 2.0, novos tipos foram adicionados, incluindo tipos complexos como ARRAY, MAP e STRUCT. Para mais detalhes sobre as edições de tipos de dados, consulte Edições de tipos de dados.
|
Tipo do MaxCompute |
Tipo Java |
Tipo Java Writable |
|
TINYINT |
java.lang.Byte |
ByteWritable |
|
SMALLINT |
java.lang.Short |
ShortWritable |
|
INT |
java.lang.Integer |
IntWritable |
|
BIGINT |
java.lang.Long |
LongWritable |
|
FLOAT |
java.lang.Float |
FloatWritable |
|
DOUBLE |
java.lang.Double |
DoubleWritable |
|
DECIMAL |
java.math.BigDecimal |
BigDecimalWritable |
|
BOOLEAN |
java.lang.Boolean |
BooleanWritable |
|
STRING |
java.lang.String |
Text |
|
VARCHAR |
com.aliyun.odps.data.Varchar |
VarcharWritable |
|
BINARY |
com.aliyun.odps.data.Binary |
BytesWritable |
|
DATE |
java.sql.Date |
DateWritable |
|
DATETIME |
java.util.Date |
DatetimeWritable |
|
TIMESTAMP |
java.sql.Timestamp |
TimestampWritable |
|
INTERVAL_YEAR_MONTH |
N/A |
IntervalYearMonthWritable |
|
INTERVAL_DAY_TIME |
N/A |
IntervalDayTimeWritable |
|
ARRAY |
java.util.List |
N/A |
|
MAP |
java.util.Map |
N/A |
|
STRUCT |
com.aliyun.odps.data.Struct |
N/A |
O tipo Java byte[] não consta na lista de tipos suportados. Se você usar byte[] como parâmetro de entrada ou valor de retorno de um método evaluate, o erro ODPS-0130071 será reportado. Para processar dados binários em uma UDF, use os tipos Java correspondentes ao tipo BINARY do MaxCompute: com.aliyun.odps.data.Binary para o tipo Java padrão, ou com.aliyun.odps.io.BytesWritable para o tipo Writable. Alternativamente, converta os dados binários para uma string codificada em Base64 e use o tipo String como valor de retorno.
Compatibilidade com UDFs do Hive
Caso seu projeto do MaxCompute use a edição de tipos de dados 2.0, o sistema suporta UDFs no estilo Hive. Assim, é possível usar diretamente UDFs do Hive desenvolvidas em versões compatíveis com o MaxCompute.
A versão compatível do Hive é a 2.1.0, correspondente ao Hadoop 2.7.2. Se sua UDF foi compilada em uma versão diferente do Hive ou Hadoop, recompile o arquivo JAR usando Hive 2.1.0 ou Hadoop 2.7.2.
Para um exemplo detalhado de uso de UDFs do Hive no MaxCompute, consulte Exemplo de UDF: Compatibilidade com Hive.