Se as funções integradas do MaxCompute não atenderem às suas necessidades, crie uma função definida pelo usuário (UDF) em Java com ferramentas de desenvolvimento como IntelliJ IDEA (Maven) ou MaxCompute Studio e chame-a em instruções SQL do MaxCompute.
Limites
-
Acesso à Internet por meio de UDFs
Por padrão, o MaxCompute bloqueia o acesso à Internet por meio de UDFs. Para ativar esse acesso, preencha o formulário de solicitação de conexão de rede conforme seus requisitos de 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 detalhes sobre o preenchimento do formulário, consulte Network connection process.
-
Acesso a uma VPC por meio de UDFs
Por padrão, o MaxCompute bloqueia o acesso a recursos em VPCs por meio de UDFs. Para acessar esses recursos, 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 com UDFs, UDAFs ou UDTFs
Não utilize UDFs, UDAFs ou UDTFs para ler 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, familiarize-se com a estrutura de código da UDF e com os mapeamentos de tipos de dados entre Java e MaxCompute. Para mais informações, consulte o Apêndice: Tipos de dados.
Ao desenvolver uma 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, 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, a chamada simultânea dessas UDFs na mesma instrução SQL fará o MaxCompute carregar aleatoriamente uma das classes. Isso pode resultar em comportamentos inesperados ou falhas de compilação.Em uma UDF Java, utilize tipos de objeto (como String e Long) para parâmetros de entrada e valores de retorno, em vez de tipos primitivos (como int e long).
Valores NULL no SQL correspondem a NULL em Java. Tipos primitivos do Java não aceitam valores NULL e, portanto, não são permitidos.
Fluxo de trabalho de desenvolvimento de UDFs
O desenvolvimento de UDFs envolve várias etapas: preparação do ambiente, escrita do código da UDF, upload do arquivo JAR, registro da UDF e depuração. As seções a seguir demonstram esse fluxo de trabalho com 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 com o 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 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 um nome de classe no campo Name e pressione Enter.
O campo 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 Lower.
-
Escreva o código da UDF no editor de código. 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 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: Projeto do MaxCompute ao qual a UDF pertence. Como a UDF foi escrita no projeto do MaxCompute conectado, use o valor padrão.
Resource file: Caminho do arquivo de recurso do qual a UDF depende. Use o valor padrão.
Resource name: Recurso do qual a UDF depende. Use o valor padrão.
Function name: 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 no projeto de destino do MaxCompute e selecione Open Console. No console, insira a instrução SQL que chama a UDF e pressione Enter. Exemplo:
select lower_test('ABC');O sistema retorna o seguinte resultado:
+-----+ | _c0 | +-----+ | abc | +-----+
Uso do DataWorks
-
Prepare o ambiente.
Para 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. 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 tópicos a seguir:
-
Depure a UDF.
Após registrar a UDF, crie um nó ODPS SQL e execute uma instrução SQL nesse 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 com 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. 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 fazer o upload do código empacotado e registrar 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 em Java conforme descrito no fluxo de trabalho de desenvolvimento de UDFs, chame-a no SQL do MaxCompute. Os métodos disponíveis são:
Uso de UDF em um projeto do MaxCompute: O método é semelhante ao uso de funções integradas. Utilize uma função definida pelo usuário da mesma forma que uma função integrada.
Uso de UDF entre projetos: Utilize uma UDF do Projeto B no Projeto A. A instrução a seguir mostra um exemplo:
select B:udf_in_other_project(arg0, arg1) as res from table_t;. Para mais informações sobre compartilhamento entre projetos, consulte Cross-project resource access based on packages.
Exemplos de UDFs
Apêndice: Estrutura de código da UDF
Uma UDF em 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ório.
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 do 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>), ondesignaturedefine os tipos de dados dos parâmetros de entrada e do valor de retorno. Ao utilizar o tipo de dados STRUCT em uma UDF, a reflexão não consegue recuperar nomes e tipos de campos decom.aliyun.odps.data.Struct. Nesse caso, utilize 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 contenham 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ório.
Esta unidade organiza o código da UDF e define as 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.Implemente múltiplos métodos
evaluate. Ao chamar a UDF, o MaxCompute seleciona o métodoevaluatecorrespondente com base nos tipos dos argumentos.Ao escrever uma UDF em Java, utilize tipos Java ou tipos Java Writable. Para mapeamentos detalhados entre tipos de dados do MaxCompute e tipos de dados Java, consulte o Apêndice: Tipos de dados.
Inicialização e limpeza da UDF: Opcional. Implemente a inicialização e a limpeza com
void setup(ExecutionContext ctx)evoid close(). O métodovoid setup(ExecutionContext ctx)é executado uma vez antes do métodoevaluatee serve para inicializar recursos ou objetos membro necessários para a computação. O métodovoid close()é executado uma vez após a conclusão de todas as chamadas deevaluatee realiza tarefas de limpeza, como fechar 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 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 que os tipos de dados utilizados em uma UDF Java sejam consistentes com os tipos de dados do MaxCompute, utilize os mapeamentos a seguir.
Os tipos de dados suportados pelo MaxCompute variam conforme a edição do tipo de dados. A partir do MaxCompute 2.0, tipos 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 consta na lista de tipos Java suportados. Se você utilizar byte[] como parâmetro de entrada ou valor de retorno de um método evaluate, o sistema reportará um erro ODPS-0130071. Para processar dados binários em uma UDF, utilize 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 utilizar o tipo String para o valor de retorno.
Compatibilidade com UDFs do Hive
Se o seu projeto do MaxCompute utilizar a edição de tipos de dados 2.0, o MaxCompute suporta UDFs no estilo Hive. Utilize diretamente 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 Hadoop 2.7.2.
Para um exemplo detalhado de uso de uma UDF do Hive no MaxCompute, consulte UDF Example: Hive Compatibility.