Caso as funções integradas do MaxCompute não atendam aos seus requisitos, crie uma função definida pelo usuário (UDF) em Java usando uma ferramenta de desenvolvimento como o IntelliJ IDEA (Maven) ou Get started with MaxCompute Studio e, em seguida, chame a UDF em instruções SQL do MaxCompute.
Limites
-
Acesso à Internet por meio de UDFs
Por padrão, o MaxCompute não permite o acesso à Internet por meio de UDFs. Para acessar a Internet usando UDFs, preencha o formulário de solicitação de conexão de rede de acordo com os requisitos do seu negócio e envie a solicitação. A equipe de suporte técnico do MaxCompute entrará em contato prontamente para ativar a conectividade de rede. Para mais informações sobre como preencher o formulário de solicitação de conexão de rede, consulte Network connection process.
-
Acesso a uma VPC por meio de UDFs
Por padrão, o MaxCompute não permite o acesso a recursos em VPC por meio de UDFs. Para usar UDFs no acesso a recursos de uma VPC, estabeleça uma conexão de rede entre o MaxCompute e a VPC. Para mais informações sobre as operações relacionadas, consulte Access VPC resources from a UDF.
-
Leitura de dados de tabelas por meio de UDFs, UDAFs ou UDTFs
Não é possível usar UDFs, UDAFs ou UDTFs para ler dados dos seguintes tipos de tabelas:
Tabelas submetidas à evolução de schema
Tabelas que contêm tipos de dados complexos
Tabelas que contêm tipos de dados json
Tabelas transacionais
Notas de uso
Antes de escrever uma UDF em Java, familiarize-se com UDF code structure e com os mapeamentos de tipos de dados entre Java e MaxCompute. Para mais informações, consulte Appendix: Data types.
Ao escrever uma UDF em Java, observe os seguintes pontos:
Evite incluir classes com o mesmo nome, mas com lógicas diferentes, em arquivos JAR de UDF distintos. Por exemplo, se UDF1 e UDF2 corresponderem a udf1.jar e udf2.jar, respectivamente, e ambos os arquivos JAR contiverem
com.aliyun.UserFunction.classcom lógicas diferentes, chamar ambas as UDFs na mesma instrução SQL fará com que o MaxCompute carregue aleatoriamente uma das classes. Isso pode levar a resultados inesperados ou a uma falha de compilação.Em uma UDF Java, os parâmetros de entrada e os valores de retorno devem usar tipos de objeto (como String e Long), e não tipos primitivos (como int e long).
Os valores NULL em SQL são mapeados para NULL em Java. Os tipos primitivos do Java não podem representar valores NULL e, portanto, não são permitidos.
Fluxo de trabalho de desenvolvimento de UDFs
O desenvolvimento de UDFs envolve várias etapas: preparar o ambiente, escrever o código da UDF, fazer o upload do arquivo JAR, registrar a UDF e depurar. As seções a seguir demonstram esse fluxo de trabalho com o MaxCompute Studio, DataWorks e odpscmd.
Uso do MaxCompute Studio
O exemplo a seguir mostra como desenvolver e chamar uma UDF Java que converte caracteres para minúsculas usando o MaxCompute Studio.
-
Prepare o ambiente.
Antes de 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 seguintes tópicos:
-
Escreva o código da UDF.
No explorador Project, clique com o botão direito do mouse no diretório de source 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.
Name especifica o nome da classe Java do MaxCompute a ser criada. Caso ainda não tenha criado um pacote, insira packagename.classname para criar um automaticamente. Neste exemplo, a classe recebe o nome de Lower.
-
Escreva o código da UDF no editor de código. Por 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 Develop and debug UDFs.
-
Faça o upload e registre a UDF.
Clique com o botão direito do mouse no arquivo Java da UDF e selecione Deploy to server.... Na caixa de diálogo Package a jar, envie resource and register function, configure os parâmetros e clique em OK.
MaxCompute project: o projeto do MaxCompute ao qual a UDF pertence. Como a UDF é escrita no projeto do MaxCompute conectado, use o valor padrão.
Resource file: o caminho do arquivo de recurso do qual a UDF depende. Use o valor padrão.
Resource name: o recurso do qual a UDF depende. Use o valor padrão.
Function name: o nome usado para chamar a UDF nas instruções SQL. Por exemplo, Lower_test.
-
Depure a UDF.
No painel de navegação à esquerda, clique em Project Explore. Clique com o botão direito do mouse no projeto do MaxCompute de destino e selecione Open console. No console, insira a instrução SQL que chama a UDF e pressione Enter. Por exemplo:
select lower_test('ABC');O resultado retornado é o seguinte:
+-----+ | _c0 | +-----+ | abc | +-----+
Uso do DataWorks
-
Prepare o ambiente.
Antes de desenvolver e depurar uma UDF no DataWorks, ative o DataWorks e vincule um projeto do MaxCompute a ele. Para mais informações, consulte Use DataWorks.
-
Escreva o código da UDF.
Escreva o código da UDF em qualquer ferramenta de desenvolvimento Java e empacote-o como um arquivo JAR. Por 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.
Faça o upload do código empacotado para o DataWorks e registre a UDF. Para mais informações, consulte os seguintes tópicos:
-
Depure a UDF.
Após registrar a UDF, crie um nó ODPS SQL e execute uma instrução SQL no nó para depurar a UDF. Para mais informações sobre como criar um nó ODPS SQL, consulte Create an ODPS SQL node. Exemplo:
select lower_test('ABC');
Uso do odpscmd
-
Prepare o ambiente.
Para desenvolver e depurar uma UDF usando o odpscmd, instale o cliente e configure sua conexão com um projeto do MaxCompute. Para mais informações, consulte Use the MaxCompute client (odpscmd).
-
Escreva o código da UDF.
Escreva o código da UDF em qualquer ferramenta de desenvolvimento Java e empacote-o como um arquivo JAR. Por 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.
Faça o upload do código empacotado usando o odpscmd e registre a UDF. Para mais informações, consulte:
-
Depure a UDF.
Após registrar a UDF, escreva e execute uma instrução SQL para depurá-la. Exemplo:
select lower_test('ABC');
Chamada de UDFs
Após desenvolver uma UDF Java conforme descrito em UDF development workflow, chame-a no MaxCompute SQL. Os seguintes métodos estão disponíveis:
Uso de uma UDF em um projeto do MaxCompute: o método é semelhante ao uso de built-in functions. Use uma função definida pelo usuário da mesma forma que usa uma função integrada.
Uso de uma UDF entre projetos: use uma UDF do Projeto B no Projeto A. A seguinte instrução mostra um exemplo:
select B:udf_in_other_project(arg0, arg1) as res from table_t;. Para mais informações sobre o compartilhamento entre projetos, consulte Cross-project resource access based on packages.
Exemplos de UDFs
Apêndice: Estrutura de código da UDF
Uma UDF Java consiste nas seguintes partes:
-
Pacote Java: opcional.
Agrupe suas classes Java em um pacote para facilitar a reutilização e a organização.
-
Herança da classe UDF: obrigatória.
A classe base obrigatória é
com.aliyun.odps.udf.UDF. Caso precise de outras classes UDF ou tipos de dados complexos, adicione as classes necessárias de MaxCompute SDK. Por exemplo, a classe para o tipo de dados STRUCT écom.aliyun.odps.data.Struct. -
Anotação
@Resolve: opcional.O formato é
@Resolve(<signature>), em quesignaturedefine os tipos de dados dos parâmetros de entrada e do valor de retorno. Ao usar o tipo de dados STRUCT em uma UDF, a reflexão não consegue recuperar os nomes e os tipos dos campos decom.aliyun.odps.data.Struct. Nesse caso, use a anotação@Resolvepara recuperá-los. Se usar STRUCT em uma UDF, adicione a anotação@Resolveà classe da UDF. A anotação afeta apenas as sobrecargas cujos parâmetros ou valores de retorno contêm com.aliyun.odps.data.Struct. Exemplo:@Resolve("struct<a:string>,string->string"). Para um exemplo detalhado, consulte UDF Example: Complex Data Types. -
Classe Java personalizada: obrigatória.
Esta é a unidade que organiza o código da sua UDF e define as variáveis e os métodos que implementam a lógica do seu 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.Implemente vários métodos
evaluate. Ao chamar a UDF, o MaxCompute seleciona o métodoevaluatecorrespondente com base nos tipos de argumento.Ao escrever uma UDF Java, use tipos Java ou tipos Java Writable. Para mapeamentos detalhados entre os tipos de dados do MaxCompute e os tipos de dados Java, consulte Appendix: Data types.
Inicialização e limpeza da UDF: opcional. Implemente a inicialização e a limpeza usando
void setup(ExecutionContext ctx)evoid close(). O métodovoid setup(ExecutionContext ctx)é chamado uma vez antes do métodoevaluatee pode ser usado para inicializar recursos ou objetos membro necessários para a computação. O métodovoid close()é chamado uma vez após a conclusão de todas as chamadasevaluatee é usado para tarefas de limpeza, como o fechamento de arquivos.
Os exemplos a seguir mostram 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 oferece suporte a UDFs desenvolvidas para sua versão compatível com o Hive. Para mais informações, consulte Hive UDF compatibility.
Apêndice: Tipos de dados
Mapeamentos de tipos de dados
Para garantir que os tipos de dados usados em uma UDF Java sejam consistentes com os tipos de dados do MaxCompute, use os seguintes mapeamentos.
Os tipos de dados suportados pelo MaxCompute variam de acordo com a edição do tipo de dados. A partir do MaxCompute 2.0, tipos de dados adicionais estão disponíveis, incluindo tipos complexos como ARRAY, MAP e STRUCT. Para mais informações, consulte Data type editions.
|
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 está na lista de tipos Java suportados. Caso use byte[] para um parâmetro de entrada ou para o valor de retorno de um método evaluate, o sistema relatará o erro ODPS-0130071. 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. Também é possível converter dados binários em uma string codificada em Base64 e usar o tipo String para o valor de retorno.
Compatibilidade com UDFs do Hive
Se o seu projeto do MaxCompute usar a edição de tipos de dados 2.0, o MaxCompute oferecerá suporte a UDFs no estilo do Hive. Use diretamente as UDFs do Hive desenvolvidas para uma versão compatível do Hive.
A versão compatível do Hive é a 2.1.0, que corresponde ao Hadoop 2.7.2. Caso sua UDF tenha sido compilada em uma versão diferente do Hive ou do Hadoop, recompile o arquivo JAR da UDF com o Hive 2.1.0 ou o Hadoop 2.7.2.
Para um exemplo detalhado de uso de uma UDF do Hive no MaxCompute, consulte UDF Example: Hive Compatibility.