Una función escalar definida por el usuario (UDSF) asigna cero, uno o más valores escalares a un único valor escalar. Cada fila de entrada produce exactamente un valor de salida.
Este tema describe cómo crear, registrar y utilizar una UDSF de Python en Realtime Compute for Apache Flink.
Límites
A continuación se describen las restricciones aplicables al desarrollar funciones definidas por el usuario (UDF) de Python en Realtime Compute for Apache Flink:
|
Restricción |
Requisito |
|
Versión de Apache Flink |
1.12 y posteriores |
|
Versión de Python |
Preinstalada en cada espacio de trabajo. VVR anterior a 8.0.11: Python 3.7.9. VVR 8.0.11 y posteriores: Python 3.9.21. |
|
Versión de JDK |
JDK 8 y JDK 11. Los paquetes JAR de terceros deben ser compatibles con JDK 8 o JDK 11. |
|
Versión de Scala |
Solo Scala 2.11 de código abierto. Los paquetes JAR de terceros deben ser compatibles con Scala 2.11. |
|
Funciones en línea |
Compatible solo con VVR 11.9-preview1 y versiones posteriores. |
Después de actualizar a VVR 8.0.11 o posterior, pruebe, despliegue y ejecute nuevamente sus borradores existentes de PyFlink para confirmar su compatibilidad.
Métodos de desarrollo
Puede desarrollar una UDSF de Python de cualquiera de las siguientes maneras:
Empaquete su código de Python, cargue el paquete y regístrelo como una función en la plataforma.
Declare la lógica del código como una función en línea dentro de una sentencia SQL.
Si la lógica de su UDSF es sencilla, considere desarrollarla como una función en línea.
Crear una UDSF
Los siguientes pasos utilizan Windows como entorno de ejemplo. Flink proporciona un repositorio de ejemplos que incluye implementaciones de UDSF, funciones de agregación definidas por el usuario (UDAF) y funciones con valor de tabla definidas por el usuario (UDTF).
-
Descargue y descomprima python_demo-master en su computadora local.
Este es un repositorio de GitHub de terceros. El acceso puede ser lento o intermitente.
En PyCharm, seleccione File > Open y abra el directorio descomprimido
python_demo-master.-
Abra
udfs.pyen la ruta\python_demo-master\udxy defina su UDSF.from pyflink.table import DataTypes from pyflink.table.udf import udf @udf(result_type=DataTypes.STRING()) def sub_string(s: str, begin: int, end: int): return s[begin:end]El ejemplo
sub_stringextrae caracteres desde la posiciónbeginhasta la posiciónenden la cadena de entrada. -
Desde el directorio
\python_demo-master, ejecute el siguiente comando para empaquetar el directorioudx:zip -r python_demo.zip udxCuando aparezca
python_demo.zipen\python_demo-master\, el paquete está listo.
Registrar una UDSF
Después de crear el paquete, registre la UDSF en la consola de Realtime Compute for Apache Flink. Para consultar los pasos de registro, véase Manage user-defined functions (UDFs).
Utilizar una UDSF
Una vez registrada la UDSF, utilícela en un trabajo de Flink SQL.
-
Cree un borrador mediante Flink SQL. Para más detalles, consulte Job development overview. El siguiente ejemplo llama a
ASI_UDSF(el nombre registrado de su UDSF) para extraer los caracteres de las posiciones 2 a 4 del campoaen la tabla de origen:CREATE TEMPORARY TABLE ASI_UDSF_Source ( a VARCHAR, b INT, c INT ) WITH ( 'connector' = 'datagen' ); CREATE TEMPORARY TABLE ASI_UDSF_Sink ( a VARCHAR ) WITH ( 'connector' = 'blackhole' ); INSERT INTO ASI_UDSF_Sink SELECT ASI_UDSF(a, 2, 4) FROM ASI_UDSF_Source; En el panel de navegación izquierdo de la consola de desarrollo, seleccione O&M > Deployments. Localice el despliegue y haga clic en Start en la columna Actions. Una vez iniciado el despliegue, los caracteres en las posiciones 2–4 del campo
aenASI_UDSF_Sourcese escriben enASI_UDSF_Sink.
Funciones escalares en línea de Python
Una función en línea integra su implementación directamente en una sentencia CREATE FUNCTION, por lo que la función se define y registra dentro de la misma sentencia SQL. El siguiente ejemplo define una función en línea que oculta parcialmente direcciones de correo electrónico. Declare la lógica completa del código entre los delimitadores $$.
CREATE TEMPORARY FUNCTION mask_email(email STRING)
RETURNS STRING AS $$
if email is None:
return None
name, separator, domain = email.partition("@")
if not separator:
return email
return name[:1] + "***@" + domain
$$ LANGUAGE PYTHON;
Python es sensible a la sangría. Inicie el código de primer nivel del cuerpo de la función en la columna 0 y mantenga la sangría relativa correcta dentro de los bloques de código.
Las funciones en línea no admiten ejecución vectorizada y no pueden declararse como funciones no deterministas.
Solo se admiten funciones TEMPORARY. Aún no es posible conservar las definiciones de funciones en la plataforma.
Funciones definidas por el usuario asíncronas
Para las UDF que realizan operaciones intensivas en E/S, como el acceso a bases de datos externas o solicitudes HTTP, utilice funciones definidas por el usuario asíncronas. Una sola UDF asíncrona puede gestionar múltiples solicitudes de E/S simultáneamente, lo que distribuye el tiempo de espera entre las solicitudes y mejora el throughput del trabajo.
Límites
-
Compatible solo con VVR 11.7 y versiones posteriores. Se requiere VVR PyFlink 11.7 o superior. Para más detalles, consulte ververica-flink.
pip3 install "ververica-flink>=11.7" Solo se admiten funciones escalares definidas por el usuario (UDSF) asíncronas.
Solo se admite el modo de proceso de Python, es decir,
python.execution-mode=process.Las funciones definidas por el usuario asíncronas de Pandas aún no son compatibles.
Las funciones en línea aún no son compatibles.
Uso
Una función definida por el usuario asíncrona puede implementarse como una función async de Python o como una subclase de la clase de función asíncrona. A continuación se muestra un código de ejemplo.
import asyncio
from pyflink.table import DataTypes
from pyflink.table.udf import AsyncScalarFunction, udf
# Method 1: Use a Python async function
@udf(result_type=DataTypes.STRING())
async def async_api_call(product_id: str) -> str:
await asyncio.sleep(0.05)
return f"product_{product_id}"
# Method 2: Subclass the asynchronous function class
class AsyncUserLookup(AsyncScalarFunction):
def open(self, function_context):
self.cache = {}
async def eval(self, user_id: str) -> str:
if user_id in self.cache:
return self.cache[user_id]
await asyncio.sleep(0.05)
result = f"user_{user_id}"
self.cache[user_id] = result
return result
def close(self):
self.cache.clear()
async_user_lookup = udf(
AsyncUserLookup(),
input_types=[DataTypes.STRING()],
result_type=DataTypes.STRING()
)
Las funciones definidas por el usuario asíncronas se registran y utilizan de la misma manera que las funciones síncronas.
Parámetros de configuración
Los siguientes parámetros controlan el comportamiento en tiempo de ejecución de las funciones definidas por el usuario asíncronas.
|
Parámetro |
Valor predeterminado |
Descripción |
|
table.exec.async-scalar.max-concurrent-operations |
10 |
Número máximo de llamadas asíncronas simultáneas por instancia de operador. Valor predeterminado: 10. |
|
table.exec.async-scalar.timeout |
3 min |
Tiempo de espera para una sola llamada asíncrona. |
|
table.exec.async-scalar.retry-strategy |
FIXED_DELAY |
Estrategia de reintento tras un error en la llamada asíncrona. Valores admitidos:
|
|
table.exec.async-scalar.retry-delay |
100 ms |
Tiempo de espera para los reintentos con retraso fijo. Nota
Válido únicamente cuando table.exec.async-scalar.retry-strategy se establece en FIXED_DELAY. |
|
table.exec.async-scalar.max-attempts |
3 |
Número máximo de intentos antes de considerar que una llamada asíncrona ha fallado. Nota
Válido únicamente cuando table.exec.async-scalar.retry-strategy se establece en FIXED_DELAY. |