Remote UDFs

更新时间:
复制 MD 格式

Starting with V3.1, Hologres supports remote calls to user-defined functions in Function Compute (FC) to process complex business logic or perform advanced data operations. This topic describes how to use Remote UDFs in Hologres.

Overview

Remote functions extend the data processing and analysis capabilities of Hologres by integrating external functions from services like Alibaba Cloud Function Compute (FC). This integration allows you to dynamically call FC functions when querying Hologres data to process complex business logic or perform advanced data operations.

Remote functions support the following use cases:

  • Real-time data processing: Call external functions during data queries to perform data cleansing, format conversion, or complex calculations.

  • Third-party service integration: Use Function Compute to interact with other Alibaba Cloud services or third-party APIs, using your Hologres data.

  • Advanced analytics: Use Function Compute to run advanced analytics algorithms, such as model inference and machine learning, and write the results directly back to Hologres.

Prerequisites

  • You have a Hologres instance of V3.1 or later. For more information, see Purchase a Hologres instance.

  • You have activated Function Compute and are using a V3.0 instance. To activate the service, log on to the Function Compute console.

  • The AliyunServiceRoleForHologresRemoteUDF service-linked role is authorized.

    1. Log on to the Hologres console. In the left-side navigation pane, click Create a Service-linked Role.

    2. Select AliyunServiceRoleForHologresRemoteUDF and click Authorize Now.

Note
  • The Hologres instance and Function Compute service must be in the same region.

  • Activate Alibaba Cloud Function Compute, and develop and deploy the function to be called by Hologres. For details, see Code development overview.

Limitations

  • Only scalar UDFs and user-defined table-valued functions (UDTFs) are supported. User-defined aggregate functions (UDAFs) are not supported.

  • Only the following data types and their corresponding array types are supported: BOOLEAN, INTEGER, BIGINT, REAL, DOUBLE PRECISION, and TEXT.

  • Remote functions do not support constant input parameters.

  • This feature incurs costs in Function Compute (FC). For more information, see Billing.

  • This feature does not incur extra costs in Hologres.

  • Remote UDFs can be executed only in the Hologres query engine (HQE). They cannot be used in the same SQL statement with built-in functions that are executed only in the PostgreSQL-compatible query engine (PQE), such as encryption and decryption (PGCRYPTO) extension functions. Using them together causes an engine execution conflict and returns the following error.

    ERROR: ORCA failed to produce a plan : No plan has been computed for required properties

    To use a Remote UDF and a PQE-only built-in function at the same time, split the operations into separate SQL statements and execute them individually.

Manage remote UDFs

Create an extension

To use remote functions, you must first create an extension by running the following command:

CREATE EXTENSION [ IF NOT EXISTS ] function_compute;

Create a function

Syntax

CREATE [ OR REPLACE ] FUNCTION <function_name>
  ( [ [ argmode ] [ argname ] <argtype> [ { DEFAULT | = } default_expr ] [, ...] ] )
    [ RETURNS [SETOF] rettype | RETURNS TABLE ( column_name column_type) ]
  LANGUAGE function_compute
  AS '<fc_endpoint>/<func_name>'
  {
    { CALLED ON NULL INPUT | RETURNS NULL ON NULL INPUT | STRICT }
    | SET function_compute.qualifier TO <qualifier>
    | SET function_compute.compression TO <compression>
    | SET function_compute.max_batch_size TO <max_batch_size>
  } ...

Parameters

Category

Parameter

Required

Description

Function name

function_name

Yes

The name of the function.

  • The function name must be unique within the same schema and cannot conflict with an existing function that has the same parameter types. However, function overloading with different parameter types is supported. For example, you can create rf_sum(int) and rf_sum(float).

  • To avoid conflicts, we recommend that you add the rf_ prefix to the names of remote functions.

  • If you specify a schema, such as schema1.func, the function is created in that schema.

  • When you use CREATE OR REPLACE FUNCTION to replace a function, you cannot change the function name, parameter types, or return type. You must drop and re-create the function instead.

Function parameters

argtype

Yes

The data type of the parameter.

argmode

No

Valid values are IN, OUT, and INOUT. The default is IN. To avoid ambiguity, we recommend that you do not use INOUT. A function can have only one OUT or INOUT parameter.

argname

No

The name of the parameter.

  • For input parameters, the name is for documentation purposes only.

  • For output parameters, the name determines the column name in the result set. If this parameter is omitted, the system generates a default name.

default_expr

No

The default value. This applies only to input parameters. If a parameter has a default value, all subsequent parameters must also have default values.

FC endpoint

LANGUAGE function_compute

Yes

Specifies that the function uses the Function Compute service.

fc_endpoint

Yes

The internal endpoint for Function Compute. For more information, see Endpoints.

func_name

Yes

The name of the target function, which must be created in the Function Compute console in advance.

Return type

rettype

No

The data type of the return value.

If you use OUT or INOUT parameters, you can omit the RETURNS clause. If specified, this clause must be consistent with the result type implied by the output parameters.

column_name

No

In the RETURNS TABLE syntax, this is the name of an output column.

This is another way to declare named OUT parameters. The difference is that RETURNS TABLE also implies RETURNS SETOF, meaning the function returns a set.

column_type

No

In the RETURNS TABLE syntax, this is the data type of an output column.

Null-handling policy

CALLED ON NULL INPUT

No

The default behavior. The function is called even for NULL inputs and must handle the null logic itself.

RETURNS NULL ON NULL INPUT

No

Returns NULL immediately if any input is NULL.

STRICT

No

An alias for RETURNS NULL ON NULL INPUT.

Function version control

qualifier

No

Specifies the function version or alias to call. The default value is LATEST.

Request compression algorithm

compression

No

Specifies the compression algorithm for the function call request and response. Valid values:

  • None: Compression is disabled. This is the default.

  • GZIP: GZIP compression is enabled.

Maximum batch size per request

max_batch_size

No

Specifies the maximum number of rows to send to FC in each batch.

Use this setting to cap the batch size for FC functions that have memory limits or other constraints. If you do not specify this parameter, Hologres automatically calculates and uses the optimal batch size. In most cases, you do not need to set this parameter.

Examples

  • Create a scalar UDF.

    CREATE OR REPLACE FUNCTION rf_add (  
      a INTEGER,  
      b INTEGER DEFAULT 1 
    )  
    RETURNS BIGINT  
    LANGUAGE function_compute  
    AS 'xxxxxxxxxxxxx.cn-shanghai-internal.fc.aliyuncs.com/add'  
    ;
  • Create a UDTF.

    -- Method 1
    CREATE OR REPLACE FUNCTION rf_unnest(TEXT [])
    RETURNS TABLE (item TEXT )
    LANGUAGE function_compute
    AS 'xxxxxxxxxxxxxx.cn-hangzhou-internal.fc.aliyuncs.com/unnest'
    STRICT
    SET function_compute.max_batch_size TO 1024;
    -- Method 2
    CREATE OR REPLACE FUNCTION rf_unnest(TEXT []) 
    RETURNS SETOF TEXT 
    LANGUAGE function_compute 
    AS 'xxxxxxxxxxxxxx.cn-hangzhou-internal.fc.aliyuncs.com/unnest' 
    STRICT
    SET function_compute.max_batch_size TO 1024;

View functions

View the created remote functions.

SELECT
  CASE
    WHEN p.proretset = 'f' THEN 'scalar UDF'
    WHEN p.proretset = 't' THEN 'UDTF'
  END AS function_type,
  n.nspname AS schema_name,
  p.proname AS function_name,
  pg_get_function_arguments(p.oid) AS arguments,
  pg_get_function_result(p.oid) AS return_type,
  p.proisstrict AS is_strict,
  p.proconfig AS config,
  pg_get_functiondef(p.oid) AS definition
FROM
  pg_proc p
  JOIN pg_language l ON p.prolang = l.oid
  JOIN pg_namespace n ON p.pronamespace = n.oid
WHERE
  l.lanname = 'function_compute'
  AND p.prokind != 'p'
ORDER BY
  function_type,
  schema_name,
  function_name;

Delete a function

Syntax

 DROP FUNCTION [ IF EXISTS ] <function_name> [ ( [ [ argmode ] [ argname ] <argtype> [, ...] ] ) ] [, ...]

Parameters

Parameter

Required

Description

function_name

Yes

The name of the function to delete.

argtype

Yes

The data type of the parameter.

argmode

No

Valid values are IN, OUT, and INOUT. The default is IN. To avoid ambiguity, we recommend that you do not use INOUT. A function can have only one OUT or INOUT parameter.

argname

No

The name of the parameter. For input parameters, the name is for documentation purposes only. For output parameters, the name determines the column name in the result set. If omitted, the system generates a default name.

Example

DROP FUNCTION rf_add(INTEGER, INTEGER);

Data exchange format

Request format: Hologres to FC

Hologres calls the InvokeFunction API of Function Compute by sending a POST request. The request body is a JSON object. This object contains a single key named data. Its value is a two-dimensional array, where each inner array represents a row of data in the batch and contains the parameters for the function call.

Data serialization rules

  • BOOLEAN is serialized to a JSON boolean.

  • INTEGER and BIGINT are serialized to a JSON number.

  • REAL and DOUBLE PRECISION are serialized to a JSON number.

  • TEXT is serialized to a JSON string.

  • A SQL NULL value is serialized to a JSON null.

Example

The following code shows a sample serialized request for a remote function with the signature rf_demo(TEXT, INTEGER, BOOLEAN).

{  
  "data": [  
    ["foo", 100, true],
    [null, null, false],
    ["bar", 200, false]
  ]
}  

Response format: FC to Hologres

After Function Compute processes a batch of data, it must return the results to Hologres in JSON format as follows:

  • Scalar UDF

    • The top-level object must contain a results field. Its value must be an array, where each element corresponds to the result for a row of input data.

    • Each row result must be an array, and the order of results must match the order of input rows. For example, the Nth element in the results array corresponds to the Nth input row.

    The following code shows a sample response for a batch of four rows:

    {
      "results": [
        ["Beijing"],
        ["Shanghai"],
        ["Shenzhen"],
        ["Guangzhou"]
      ]
    }
  • A user-defined table-valued function (UDTF) supports single-row input to generate multi-row output. A row number (row_num) is required to identify the relationship with the original input row.

    • The top-level object must contain a results field. Its value must be an array, where each element corresponds to one row of output data.

    • Each row result must be an array that contains two elements:

      • row_num (first element): The 0-based index of the original input row, used to associate input with output. The row_num values must be returned in ascending order.

      • result (second element): The value of a single output row.

    Example:

    {
      "results": [
        [0, "Beijing"],
        [1, "Shanghai"],
        [3, "Shenzhen"],
        [3, "Guangzhou"],
      ]
    }

Example

This example uses the unnest function.

  1. Activate Function Compute.

    Log on to the Function Compute console. You can also claim a free resource package based on the on-screen prompts. For more information, see Free Tier.

  2. Create an FC Event Function.

    1. In the left-side navigation pane, click Functions. Switch to the region where your Hologres instance resides.

    2. On the Functions page, click Create Function. The Create Function page opens.

    3. Select Event Function and configure the following parameters. Retain the default settings for other parameters. For more information, see Create an event-triggered function.

      Parameter

      Description

      Function name

      A custom name. For example, unnest.

      Runtime

      Select Built-in Runtimes / Python / Python 3.10.

      Code upload method

      Select Upload ZIP.

      Code package

      Upload the code package.

      Save the following code as unnest.py and compress it into a file named unnest.zip.

      import json
      
      def unnest(event, context):
          evt = json.loads(event)
          data = evt.get('data', None)
          if data is None:
              raise ValueError('no "data" key in event.')
          if not isinstance(data, list):
              raise ValueError('data is not a list.')
      
          res = list()
          for i in range(len(data)):
              if len(data[i]) != 1 or not isinstance(data[i], list):
                  raise ValueError('the item in data is not a list.')
              for item in data[i][0]:
                  res.append([i, item])
      
          return json.dumps({'results': res})

      Handler

      Enter unnest.unnest.

  3. Create a Hologres remote function.

    Note

    Perform the following steps in HoloWeb. For more information, see Connect to HoloWeb.

    CREATE EXTENSION IF NOT EXISTS function_compute;
    CREATE OR REPLACE FUNCTION rf_unnest(INTEGER [])
      RETURNS SETOF INTEGER
    STRICT
    LANGUAGE function_compute
    AS 'xxxxxxxxxxxxxxxxx.cn-shanghai-internal.fc.aliyuncs.com/unnest';
  4. Prepare test data.

    CREATE TABLE test_array (
        numbers INTEGER[]
    );
    INSERT INTO test_array (numbers) VALUES
      (ARRAY[1, 3]),
      (ARRAY[2, 4]),
      ('{}'),  
      (ARRAY[]::INTEGER[]),  
      (NULL);
  5. Call the remote function.

    SELECT numbers, rf_unnest(numbers) FROM test_array;
     numbers | rf_unnest
    ---------+-----------
     {2,4}   |         2
     {2,4}   |         4
     {1,3}   |         1
     {1,3}   |         3
    (4 rows)