Si las funciones integradas de MaxCompute no cubren sus necesidades, cree una función definida por el usuario (UDF) en Java con una herramienta de desarrollo como IntelliJ IDEA (Maven) o MaxCompute Studio. Después, invoque la UDF en las sentencias SQL de MaxCompute.
Límites
-
Acceso a internet mediante UDF
De forma predeterminada, MaxCompute no permite acceder a internet mediante UDF. Si necesita este acceso, complete el formulario de solicitud de conexión de red según sus requisitos de negocio y envíe la solicitud. El equipo de soporte técnico de MaxCompute se pondrá en contacto con usted a la brevedad para habilitar la conectividad de red. Para obtener más información sobre cómo completar el formulario de solicitud de conexión de red, consulte Network connection process.
-
Acceso a una VPC mediante UDF
De forma predeterminada, MaxCompute no permite acceder a los recursos de una VPC mediante UDF. Para lograrlo, establezca primero una conexión de red entre MaxCompute y la VPC. Para obtener más información sobre las operaciones relacionadas, consulte Access VPC resources from a UDF.
-
Lectura de datos de tablas mediante UDF, UDAF o UDTF
No es posible usar UDF, UDAF ni UDTF para leer datos de los siguientes tipos de tablas:
Tablas con evolución de esquema aplicada.
Tablas que contienen tipos de datos complejos.
Tablas que contienen tipos de datos JSON.
Tablas transaccionales.
Notas de uso
Antes de escribir una UDF en Java, familiarícese con UDF code structure y con las asignaciones de tipos de datos entre Java y MaxCompute. Para obtener más información, consulte Appendix: Data types.
Al escribir una UDF en Java, tenga en cuenta lo siguiente:
Evite incluir clases con el mismo nombre pero distinta lógica en diferentes archivos JAR de UDF. Por ejemplo, si UDF1 y UDF2 corresponden a udf1.jar y udf2.jar respectivamente, y ambos archivos JAR contienen
com.aliyun.odps.UserFunction.classcon lógicas distintas, invocar ambas UDF en la misma sentencia SQL hará que MaxCompute cargue una de las clases de forma aleatoria. Esto puede generar resultados inesperados o un error de compilación.En una UDF de Java, los parámetros de entrada y los valores de retorno deben usar tipos de objeto (como String y Long), no tipos primitivos (como int y long).
Los valores NULL en SQL se asignan a NULL en Java. Los tipos primitivos de Java no pueden representar valores NULL, por lo que no se admiten.
Flujo de trabajo de desarrollo de UDF
El desarrollo de una UDF implica varios pasos: preparar el entorno, escribir el código de la UDF, cargar el archivo JAR, registrar la UDF y depurarla. En las siguientes secciones se muestra este flujo de trabajo con MaxCompute Studio, DataWorks y odpscmd.
Uso de MaxCompute Studio
A continuación se muestra cómo desarrollar e invocar una UDF en Java que convierte caracteres a minúsculas mediante MaxCompute Studio.
-
Prepare el entorno.
Para desarrollar y depurar una UDF en MaxCompute Studio, instale esta herramienta y conéctela a un proyecto de MaxCompute. Para obtener más información, consulte los siguientes temas:
-
Escriba el código de la UDF.
En el explorador Project, haga clic derecho en el directorio de código fuente del módulo () y seleccione .
-
En el cuadro de diálogo Create new MaxCompute java class, haga clic en UDF, introduzca un nombre de clase en el campo Name y presione Entrar.
El campo Name especifica el nombre de la clase Java de MaxCompute que se va a crear. Si aún no ha creado un paquete, introduzca packagename.classname para generarlo automáticamente. En este ejemplo, la clase se llama Lower.
-
Escriba el código de la UDF en el editor. Por ejemplo:
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 la UDF de Java de forma local, consulte Develop and debug UDFs.
-
Cargue y registre la UDF.
Haga clic derecho en el archivo Java de la UDF y seleccione Deploy to server.... En el cuadro de diálogo Package a jar, submit resource and register function, configure los parámetros y haga clic en OK.
MaxCompute project: el proyecto de MaxCompute al que pertenece la UDF. Como la UDF se escribió en el proyecto conectado, puede dejar el valor predeterminado.
Resource file: la ruta del archivo de recurso del que depende la UDF. Puede dejar el valor predeterminado.
Resource name: el recurso del que depende la UDF. Puede dejar el valor predeterminado.
Function name: el nombre que se usará para invocar la UDF en las sentencias SQL. Por ejemplo, Lower_test.
-
Depure la UDF.
En el panel de navegación izquierdo, haga clic en Project Explore. Haga clic derecho en el proyecto de MaxCompute de destino y seleccione Open Console. En la consola, introduzca la sentencia SQL que invoca la UDF y presione Entrar. Por ejemplo:
select lower_test('ABC');Se devuelve el siguiente resultado.
+-----+ | _c0 | +-----+ | abc | +-----+
Uso de DataWorks
-
Prepare el entorno.
Para desarrollar y depurar una UDF en DataWorks, active este servicio y vincúlele un proyecto de MaxCompute. Para obtener más información, consulte Use DataWorks.
-
Escriba el código de la UDF.
Puede escribir el código de la UDF en cualquier herramienta de desarrollo de Java y empaquetarlo como un archivo JAR. Por ejemplo:
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(); } } -
Cargue y registre la UDF.
Cargue el código empaquetado en DataWorks y registre la UDF. Para obtener más información, consulte los siguientes temas:
-
Depure la UDF.
Una vez registrada la UDF, cree un nodo ODPS SQL y ejecute una sentencia SQL en él para depurarla. Para obtener más información sobre cómo crear un nodo ODPS SQL, consulte Create an ODPS SQL node. Ejemplo:
select lower_test('ABC');
Uso de odpscmd
-
Prepare el entorno.
Para desarrollar y depurar una UDF con odpscmd, instale el cliente y configure su conexión a un proyecto de MaxCompute. Para obtener más información, consulte Use the MaxCompute client (odpscmd).
-
Escriba el código de la UDF.
Puede escribir el código de la UDF en cualquier herramienta de desarrollo de Java y empaquetarlo como un archivo JAR. Por ejemplo:
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(); } } -
Cargue y registre la UDF.
Cargue el código empaquetado mediante odpscmd y registre la UDF. Para obtener más información, consulte:
-
Depure la UDF.
Una vez registrada la UDF, escriba y ejecute una sentencia SQL para depurarla. Ejemplo:
select lower_test('ABC');
Invocación de UDF
Después de desarrollar una UDF en Java tal como se describe en UDF development workflow, puede invocarla en SQL de MaxCompute. Dispone de los siguientes métodos:
Usar una UDF dentro de un proyecto de MaxCompute: este método es similar al uso de built-in functions. Una función definida por el usuario se utiliza igual que una función integrada.
Usar una UDF entre proyectos: utilice una UDF del Proyecto B desde el Proyecto A. La siguiente sentencia muestra un ejemplo:
select B:udf_in_other_project(arg0, arg1) as res from table_t;. Para obtener más información sobre el uso compartido entre proyectos, consulte Cross-project resource access based on packages.
Ejemplos de UDF
Apéndice: estructura del código de una UDF
Una UDF en Java consta de las siguientes partes:
-
Paquete de Java: opcional.
Agrupe sus clases de Java en un paquete para facilitar su reutilización y organización.
-
Herencia de la clase UDF: obligatorio.
La clase base obligatoria es
com.aliyun.odps.udf.UDF. Si necesita otras clases UDF o tipos de datos complejos, agregue las clases requeridas desde MaxCompute SDK. Por ejemplo, la clase del tipo de datos STRUCT escom.aliyun.odps.data.Struct. -
Anotación
@Resolve: opcional.Su formato es
@Resolve(<signature>), dondesignaturedefine los tipos de datos de los parámetros de entrada y del valor de retorno. Cuando usa el tipo de datos STRUCT en una UDF, la reflexión no puede recuperar los nombres ni los tipos de los campos desdecom.aliyun.odps.data.Struct. En este caso, debe usar la anotación@Resolvepara obtenerlos. Si emplea STRUCT en una UDF, agregue la anotación@Resolvea la clase de la UDF. Esta anotación solo afecta a las sobrecargas cuyos parámetros o valores de retorno contienen com.aliyun.odps.data.Struct. Ejemplo:@Resolve("struct<a:string>,string->string"). Para ver un ejemplo detallado, consulte UDF Example: Complex Data Types. -
Clase de Java personalizada: obligatorio.
Esta unidad organiza el código de la UDF y define las variables y los métodos que implementan su lógica de negocio.
-
Método
evaluate: obligatorio.Su clase de Java personalizada debe incluir un método
evaluatepúblico y no estático. Los tipos de datos de sus parámetros de entrada y de su valor de retorno definen la firma SQL de la UDF.Es posible implementar varios métodos
evaluate. Al invocar la UDF, MaxCompute selecciona el métodoevaluatecoincidente según los tipos de argumento.Al escribir una UDF en Java, puede usar tipos de Java o tipos Writable de Java. Para consultar las asignaciones detalladas entre los tipos de datos de MaxCompute y los de Java, consulte Appendix: Data types.
Inicialización y limpieza de la UDF: opcional. Implemente estas tareas con
void setup(ExecutionContext ctx)yvoid close(). El métodovoid setup(ExecutionContext ctx)se ejecuta una vez antes del métodoevaluatey sirve para inicializar los recursos u objetos miembro necesarios para el cálculo. El métodovoid close()se ejecuta una vez después de que terminan todas las llamadas aevaluatey se usa para tareas de limpieza, como cerrar archivos.
A continuación se muestran ejemplos de dos tipos de UDF.
-
Uso de tipos de 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 Writable de Java
// 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; } }
MaxCompute también admite UDF desarrolladas para su versión compatible de Hive. Para obtener más información, consulte Hive UDF compatibility.
Apéndice: tipos de datos
Asignaciones de tipos de datos
Para garantizar que los tipos de datos usados en una UDF de Java coincidan con los de MaxCompute, aplique las siguientes asignaciones.
Los tipos de datos compatibles con MaxCompute varían según la edición de tipos de datos. A partir de MaxCompute 2.0, hay disponibles tipos adicionales, incluidos los complejos como ARRAY, MAP y STRUCT. Para obtener más información, consulte Data type editions.
|
Tipo de MaxCompute |
Tipo de Java |
Tipo Writable de Java |
|
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 |
El tipo byte[] de Java no aparece en la lista de tipos de Java compatibles. Si usa byte[] como parámetro de entrada o como valor de retorno de un método evaluate, se reporta el error ODPS-0130071. Para procesar datos binarios en una UDF, use los tipos de Java correspondientes al tipo BINARY de MaxCompute: com.aliyun.odps.data.Binary para el tipo estándar de Java, o com.aliyun.odps.io.BytesWritable para el tipo Writable. También puede convertir los datos binarios en una cadena codificada en Base64 y usar el tipo String como valor de retorno.
Compatibilidad con UDF de Hive
Si su proyecto de MaxCompute usa la edición de tipos de datos 2.0, la plataforma admite UDF al estilo de Hive. Puede utilizar directamente las UDF de Hive desarrolladas para una versión compatible.
La versión compatible de Hive es la 2.1.0, que corresponde a Hadoop 2.7.2. Si compiló su UDF con otra versión de Hive o de Hadoop, vuelva a compilar el archivo JAR de la UDF con Hive 2.1.0 o Hadoop 2.7.2.
Para ver un ejemplo detallado sobre el uso de una UDF de Hive en MaxCompute, consulte UDF Example: Hive Compatibility.