Realtime Compute for Apache Flink admite funciones definidas por el usuario (UDF) de Java en trabajos de Flink SQL. Conozca los tipos de UDF, el paso de parámetros y notas importantes de uso.
Notas importantes
-
Para evitar conflictos de dependencias en paquetes JAR al desarrollar UDF, considere lo siguiente:
Asegúrese de que la versión de Flink seleccionada en la página de desarrollo de SQL coincida con la versión de Flink en la dependencia del Pom.
Para las dependencias relacionadas con Flink, establezca el scope como
providedal agregar<scope>provided</scope>.Empaquete otras dependencias de terceros mediante el método Shade. Para obtener más información, consulte Apache Maven Shade Plugin.
Para obtener más información sobre los conflictos de dependencias de Flink, consulte How do I resolve Flink dependency conflicts?.
Para evitar tiempos de espera causados por llamadas frecuentes a una UDF en un trabajo de SQL, cargue el paquete JAR de la UDF como archivo de dependencia. Luego, declare la función en el trabajo con la sintaxis
CREATE TEMPORARY FUNCTION. Por ejemplo:CREATE TEMPORARY FUNCTION 'GetJson' AS 'com.soybean.function.udf.MyGetJsonObjectFunction';
Clasificaciones de UDF
Flink admite los siguientes tres tipos de UDF.
|
Clasificación |
Descripción |
|
Función escalar definida por el usuario (UDSF) |
Una UDSF asigna cero, uno o varios valores escalares a un nuevo valor escalar. Tiene una relación uno a uno entre la entrada y la salida; es decir, lee una fila de datos y genera un valor de salida. Para obtener más información, consulte User-defined scalar functions (UDSFs). |
|
Función de agregación definida por el usuario (UDAF) |
Una UDAF agrega varios registros de entrada en un único valor de salida. Para obtener más información, consulte User-defined aggregate functions (UDAFs). |
|
Función con valor de tabla definida por el usuario (UDTF) |
Una UDTF toma cero, uno o varios valores escalares como parámetros de entrada, los cuales pueden tener longitud variable. Es similar a una UDSF, pero puede devolver cualquier número de filas como salida, no solo un único valor. Las filas devueltas pueden constar de una o varias columnas. Una sola llamada a la función puede generar múltiples filas o columnas. Para obtener más información, consulte User-defined table-valued functions (UDTFs). |
Registro de UDF
Para obtener información sobre cómo registrar una UDF global, consulte Global UDFs.
Para obtener información sobre cómo registrar una UDF en el nivel de trabajo, consulte Job-level UDFs.
Paso de parámetros a una UDF
Configure parámetros para una UDF en la consola de desarrollo de Flink y haga referencia a ellos en el código de la UDF. Esto le permite modificar rápidamente los valores de los parámetros directamente en la consola.
Las UDF proporcionan un método opcional open(FunctionContext context). FunctionContext pasa elementos de configuración personalizados como parámetros. El proceso es el siguiente:
-
En la pestaña Configuration de la página de la consola de desarrollo de Flink, agregue el elemento de configuración pipeline.global-job-parameters en la sección Other Configuration de Parameters.
pipeline.global-job-parameters: | 'k1:{hi,hello}', 'k2:"str:ing,str:ing"', 'k3:"str""ing,str:ing"'FunctionContext#getJobParametersolo puede recuperar valores definidos enpipeline.global-job-parameters. Debe incluir todos los elementos de configuración que utiliza la UDF en este parámetro. A continuación se describe cómo configurar este elemento.Paso
Acción
Procedimiento
Ejemplo
Paso 1
Defina pares clave-valor.
Separe la clave y el valor con dos puntos (:) y encierre cada par clave-valor entre comillas simples (').
Nota-
Si una clave o un valor contiene dos puntos (:), encierre dicha clave o valor entre comillas dobles (").
-
Si una clave o un valor contiene dos puntos (:) o comillas dobles ("), debe escaparlo con dos comillas dobles consecutivas ("").
-
Si key = k1 y
value = {hi,hello}, defina el par como'k1:{hi,hello}'. -
Si key = k2 y
value = str:ing,str:ing, defina el par como'k2:"str:ing,str:ing"' -
Si key = k3 y
value = str"ing,str:ing, defina el par como'k3:"str""ing,str:ing"'
Paso 2
Formatee el valor final de pipeline.global-job-parameters como un archivo YAML.
Coloque cada par clave-valor en una nueva línea y sepárelos con comas (,).
Nota-
Una cadena multilínea en un archivo YAML comienza con una barra vertical (|).
-
Cada línea de una cadena multilínea en un archivo YAML debe tener la misma sangría.
pipeline.global-job-parameters: | 'k1:{hi,hello}', 'k2:"str:ing,str:ing"', 'k3:"str""ing,str:ing"' -
-
En el código de la UDF, utilice
FunctionContext#getJobParameterpara recuperar el valor de cada elemento. El siguiente código es un ejemplo.Ejemplo:
context.getJobParameter("k1", null); // Returns the string {hi,hello}. context.getJobParameter("k2", null); // Returns the string str:ing,str:ing. context.getJobParameter("k3", null); // Returns the string str"ing,str:ing. context.getJobParameter("pipeline.global-job-parameters", null); // Returns null. You can only get the content defined in pipeline.global-job-parameters, not any other job configuration item.
Parámetros con nombre
Solo Ververica Runtime (VVR) 8.0.7 y versiones posteriores admiten el uso de parámetros con nombre para implementar UDF.
Las llamadas a funciones estándar requieren todos los parámetros en el orden correcto, lo cual es propenso a errores en funciones con muchos parámetros y no permite omitir los opcionales. Los parámetros con nombre le permiten especificar solo los que necesita. El siguiente ejemplo de ScalarFunction muestra cómo usar parámetros con nombre.
// Implement a user-defined scalar function. The last two input parameters are optional (isOptional = true).
public class MyFuncWithNamedArgs extends ScalarFunction {
private static final long serialVersionUID = 1L;
public String eval(@ArgumentHint(name = "f1", isOptional = false, type = @DataTypeHint("STRING")) String f1,
@ArgumentHint(name = "f2", isOptional = true, type = @DataTypeHint("INT")) Integer i2,
@ArgumentHint(name = "f3", isOptional = true, type = @DataTypeHint("LONG")) Long l3) {
if (i2 != null) {
return "i2#" + i2;
}
if (l3 != null) {
return "l3#" + l3;
}
return "default#" + f1;
}
}
Cuando utilice esta UDF en SQL, especifique solo el parámetro obligatorio o incluya selectivamente los parámetros opcionales.
CREATE TEMPORARY FUNCTION MyNamedUdf AS 'com.aliyun.example.MyFuncWithNamedArgs';
CREATE temporary TABLE s1 (
a INT,
b BIGINT,
c VARCHAR,
d VARCHAR,
PRIMARY KEY(a) NOT ENFORCED
) WITH (
'connector' = 'datagen',
'rows-per-second'='1'
);
CREATE temporary TABLE sink (
a INT,
b VARCHAR,
c VARCHAR,
d VARCHAR
) WITH (
'connector' = 'print'
);
INSERT INTO sink
SELECT a,
-- Specify only the first required parameter
MyNamedUdf(f1 => c) arg1_res,
-- Specify the first required parameter and the second optional parameter
MyNamedUdf(f1 => c, f2 => a) arg2_res,
-- Specify the first required parameter and the third optional parameter
MyNamedUdf(f1 => c, f3 => d) arg3_res
FROM s1;
Referencias
Para ver ejemplos de desarrollo y uso de UDF de Java, consulte User-defined aggregate functions (UDAFs), User-defined scalar functions (UDSFs) y User-defined table-valued functions (UDTFs).
Para obtener información sobre cómo depurar y ajustar UDF de Python, consulte Overview.
Para ver ejemplos de desarrollo y uso de UDF de Python, consulte User-defined aggregate functions (UDAFs), User-defined scalar functions (UDSFs) y User-defined table-valued functions (UDTFs).