Python
Realtime Compute for Apache Flink supports Python user-defined functions (UDFs) in Flink SQL jobs. You can create scalar, aggregate, and table functions in Python, manage Python dependencies, and tune UDF performance.
Types of user-defined functions
|
Category |
Description |
|
user-defined scalar function (UDSF) |
A UDSF maps zero, one, or more scalar values to a new scalar value. It processes one input row to produce one output value, creating a one-to-one mapping. For more information, see User-defined scalar functions (UDSFs). |
|
user-defined aggregate function (UDAF) |
A UDAF aggregates multiple records into a single record, creating a many-to-one mapping. For more information, see User-defined aggregate functions (UDAFs). |
|
user-defined table function (UDTF) |
A UDTF accepts zero, one, or more scalar values as input parameters. Unlike a scalar function, a table function can return any number of rows, each consisting of one or more columns. For more information, see User-defined table functions (UDTFs). |
Using Python dependencies
Realtime Compute for Apache Flink clusters come pre-installed with common Python packages such as Pandas, NumPy, and PyArrow. For a list of pre-installed third-party Python packages, see Develop Python jobs. Import these packages in your function before use, as shown in the following example.
@udf(result_type=DataTypes.FLOAT())
def percentile(values: List[float], percentile: float):
import numpy as np
return np.percentile(values, percentile)
To use a third-party Python package that is not pre-installed, upload it as a dependency file when you register the Python UDF. For more information, see Manage user-defined functions (UDFs) and Use Python dependencies.
Code debugging
You can use the logging module to output log information from your Python user-defined function for troubleshooting. The following example shows how to use logging.
@udf(result_type=DataTypes.BIGINT())
def add(i, j):
logging.info("hello world")
return i + j
After the logs are generated, you can view them in the TaskManager log files. For more information, see View run logs.
Performance tuning
Preloading resources
Preload resources during function initialization to avoid reloading them on each call to the eval method. For example, you can load a large deep learning model once and then run batch predictions against it.
from pyflink.table import DataTypes
from pyflink.table.udf import ScalarFunction, udf
class Predict(ScalarFunction):
def open(self, function_context):
import pickle
with open("resources.zip/resources/model.pkl", "rb") as f:
self.model = pickle.load(f)
def eval(self, x):
return self.model.predict(x)
predict = udf(Predict(), result_type=DataTypes.DOUBLE(), func_type="pandas")
For information about how to upload Python data files, see Use Python dependencies.
Asynchronous user-defined functions
For I/O-intensive scenarios, such as accessing external databases or making HTTP service calls, use asynchronous user-defined functions. A single function instance can handle multiple requests concurrently, distributing the wait time across several calls and significantly improving job throughput. This feature is supported only in VVR 11.7 and later versions and applies only to user-defined scalar functions (UDSFs). For details, see Asynchronous user-defined functions.
Using the Pandas library
In addition to standard Python user-defined functions, Realtime Compute for Apache Flink supports Pandas user-defined functions. These functions accept Pandas data structures such as pandas.Series and pandas.DataFrame as input, allowing you to leverage high-performance libraries like Pandas and NumPy. For more information, see Vectorized User-defined Functions.
Parameters
The performance of a Python user-defined function largely depends on its implementation. If you encounter performance issues, optimize the function logic first. The following parameters also affect performance.
|
Parameter |
Description |
|
python.fn-execution.bundle.size |
Python UDFs execute asynchronously. The Java operator caches data before sending it to a Python process for execution. When the cache reaches a threshold, the data is sent to the Python process. The The default value is 100,000 records. |
|
python.fn-execution.bundle.time |
This parameter controls the maximum caching time. The cached data is sent for processing when either the record count reaches the The default value is 1,000 milliseconds. |
|
python.fn-execution.arrow.batch.size |
For Pandas UDFs, this parameter specifies the maximum number of records an Arrow batch can contain. The default value is 10,000. Note
The value of the |
Setting these parameters to excessively large values can be counterproductive. Excessive buffering during a checkpoint may cause checkpoints to take too long or fail. For more information about these parameters, see Configuration.
Related topics
-
For information about how to register, update, and delete a user-defined function, see Manage user-defined functions (UDFs).
-
For demos on how to develop and use Python user-defined functions, see User-defined aggregate functions (UDAFs), User-defined scalar functions (UDSFs), and User-defined table functions (UDTFs).
-
To learn how to use custom Python virtual environments, third-party Python packages, JAR packages, and data files in a Flink Python job, see Use Python dependencies.
-
For demos on how to develop and use Java user-defined functions, see User-defined aggregate functions (UDAFs), User-defined scalar functions (UDSFs), and User-defined table functions (UDTFs).
-
To learn how to debug and tune Java user-defined functions, see Overview.