All Products
Search
Document Center

Realtime Compute for Apache Flink:Python user-defined scalar functions (UDSFs)

Last Updated:May 22, 2026

A user-defined scalar function (UDSF) maps zero, one, or more scalar values to a single scalar value. Each input row produces exactly one output value.

This topic describes how to create, register, and use a Python UDSF in Realtime Compute for Apache Flink.

Limits

The following constraints apply when you develop Python user-defined functions (UDFs) in Realtime Compute for Apache Flink:

Constraint Requirement
Apache Flink version 1.12 and later
Python version Pre-installed on every workspace. VVR earlier than 8.0.11: Python 3.7.9. VVR 8.0.11 and later: Python 3.9.21.
JDK version JDK 8 and JDK 11. Third-party JAR packages must be compatible with JDK 8 or JDK 11.
Scala version Open-source Scala 2.11 only. Third-party JAR packages must be compatible with Scala 2.11.
Important

After upgrading to VVR 8.0.11 or later, test, deploy, and run your existing PyFlink drafts again to confirm compatibility.

Create a UDSF

The following steps use Windows as the example environment. Flink provides a sample repository that includes implementations for UDSFs, user-defined aggregate functions (UDAFs), and user-defined table-valued functions (UDTFs).
  1. Download and decompress python_demo-master to your local machine.

    This is a third-party GitHub repository. Access may be slow or intermittent.
  2. In PyCharm, choose File > Open and open the decompressed python_demo-master directory.

  3. Open udfs.py in the \python_demo-master\udx path and define your 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]

    The sub_string example extracts characters from position begin to position end in the input string.

  4. From the \python_demo-master directory, run the following command to package the udx directory:

    zip -r python_demo.zip udx

    When python_demo.zip appears in \python_demo-master\, the package is ready.

Register a UDSF

After creating the package, register the UDSF in the Realtime Compute for Apache Flink console. For registration steps, see Manage user-defined functions (UDFs).

Use a UDSF

After registering the UDSF, use it in a Flink SQL job.

  1. Create a draft using Flink SQL. For details, see Job development overview. The following example calls ASI_UDSF (the registered name of your UDSF) to extract characters from positions 2 to 4 of the a field in the source table:

    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;
  2. In the left-side navigation pane of the development console, choose O&M > Deployments. Find the deployment, then click Start in the Actions column. After the deployment starts, characters at positions 2–4 of the a field in ASI_UDSF_Source are written to ASI_UDSF_Sink.

Asynchronous user-defined functions

For UDFs that perform I/O-intensive operations such as external database access or HTTP requests, use asynchronous user-defined functions. A single asynchronous UDF can handle multiple I/O requests concurrently, distributing wait time across requests and improving job throughput.

Limits

  • Supported only on VVR 11.7 and later. VVR PyFlink 11.7 or later is required. For details, see ververica-flink.

    pip3 install "ververica-flink>=11.7"

  • Only asynchronous user-defined scalar functions (UDSFs) are supported.

  • Only Python process mode is supported, that is, python.execution-mode=process.

  • Pandas asynchronous user-defined functions are not yet supported.

Usage

An asynchronous user-defined function can be implemented as a Python async function or as a subclass of the asynchronous function class. Sample code is shown below.

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()
)

Asynchronous user-defined functions are registered and used the same way as synchronous functions.

Configuration parameters

The following parameters control the runtime behavior of asynchronous user-defined functions.

Parameter

Default value

Description

table.exec.async-scalar.max-concurrent-operations

10

The maximum number of concurrent asynchronous calls per operator instance. Default value: 10.

table.exec.async-scalar.timeout

3 min

The timeout for a single asynchronous call.

table.exec.async-scalar.retry-strategy

FIXED_DELAY

The retry strategy after an asynchronous call fails. Supported values:

  • FIXED_DELAY: Retry after a fixed wait time.

  • NO_RETRY: Do not retry.

table.exec.async-scalar.retry-delay

100 ms

The wait time for fixed-delay retries.

Note

Effective only when table.exec.async-scalar.retry-strategy is set to FIXED_DELAY.

table.exec.async-scalar.max-attempts

3

The maximum number of attempts before an asynchronous call is considered failed.

Note

Effective only when table.exec.async-scalar.retry-strategy is set to FIXED_DELAY.