CREATE EXTERNAL FUNCTION (创建外部函数) - Amazon Redshift
AWS 文档中描述的 AWS 服务或功能可能因区域而异。要查看适用于中国区域的差异,请参阅中国的 AWS 服务入门

本文属于机器翻译版本。若本译文内容与英语原文存在差异,则一律以英文原文为准。

CREATE EXTERNAL FUNCTION (创建外部函数)

为 AWS Lambda 创建基于 Amazon Redshift 的标量用户定义的函数 (UDF)。

Syntax

CREATE [ OR REPLACE ] EXTERNAL FUNCTION external_fn_name ( [data_type] [, ...] ) RETURNS data_type { VOLATILE | STABLE | IMMUTABLE } LAMBDA 'lambda_fn_name' IAM_ROLE 'iam-role-arn';

Parameters

OR REPLACE

一个子句,指定如果某个函数与已存在的函数具有相同的名称和输入参数数据类型或签名,则替换现有函数。您只能将某个函数替换为定义一组相同数据类型的新函数。您必须是超级用户才能替换函数。

如果您定义的函数与现有函数具有相同的名称,但签名不同,则创建新的函数。换而言之,函数名称将会重载。有关更多信息,请参阅重载函数名称

外部名称

外部函数的名称。如果您指定 schema 名称 (例如 myschema.myfunction),则使用指定的 schema 创建函数。否则,将在当前 schema 中创建该函数。有关有效名称的更多信息,请参阅名称和标识符

我们建议您为所有 UDF 名称添加前缀 f_。Amazon Redshift 保留 f_ 前缀作为 UDF 名称。通过使用 f_ 前缀,可帮助确保 UDF 名称现在或将来不会与 Amazon Redshift 的任何内置 SQL 函数名称冲突。有关更多信息,请参阅命名UDFs

data_type

输入参数的数据类型。有关更多信息,请参阅数据类型

RETURNS data_type

函数返回的值的数据类型。RETURNS 数据类型可以是任何标准的 Amazon Redshift 数据类型。有关更多信息,请参阅Python UDF 数据类型

VOLATILE | STABLE | IMMUTABLE

一个子句,用于向查询优化程序通知函数的不稳定性。

要获得最佳优化,请将您的函数标记为最严格的稳定性类别(对其有效)。但是,如果类别过于严格,优化程序可能会错误地跳过某些调用,从而导致结果集不正确。按照严格性顺序,从最不严格的开始,稳定性类别如下所示:

  • VOLATILE

    对于相同的参数,函数会对连续的调用返回不同的结果,甚至对于单个语句中的行也是如此。查询优化程序无法对不稳定函数的行为做出任何假设。使用不稳定函数的查询必须重新计算每个输入行的函数。

  • STABLE

    对于相同的参数,可保证函数对在单个语句内处理的所有行返回相同的结果。在不同的语句中调用时,函数可能会返回不同的结果。此类别使优化程序能够将单个语句内对该函数的多个调用优化为对该语句的单个调用。

  • IMMUTABLE

    对于相同的参数,函数始终返回相同的结果。当查询使用常量参数调用 IMMUTABLE 函数时,优化程序会预先计算函数。

LAMBDA 'lambda_fn_name'

调用的函数的名称。Amazon Redshift

IAM_ROLE 'iam-role-arn'

集群用于身份验证和授权的 AWS Identity and Access Management (IAM) 角色的 Amazon 资源名称 (ARN)。

以下显示 IAM_ROLE 参数的语法。

IAM_ROLE 'arn:aws:iam::aws-account-id:role/role-name'

Examples

使用 Node js Lambda 函数的标量 Lambda UDF 示例

以下示例创建一个名为 exfunc_sum 的外部函数,该函数采用 2 个整数作为输入参数。此函数返回总和作为整数输出。要调用的 Lambda 函数的名称是 lambda_sum。您必须指定 IAM 角色。

create external function exfunc_sum(int,int) returns int lambda 'lambda_sum' iam_role 'arn:aws:iam::123456789012:user/johndoe';

以下示例是名为 AWSlambda_sumLambda 的 函数。用于此 Lambda 函数的语言为 Node.js 12.x。

函数接收请求负载并迭代每一行。Lambda将添加单行中的所有值来计算该行的总和,该总和保存在响应数组中。结果数组中的行数类似于在请求负载中接收的行数。

JSON 响应负载必须在“results”字段中具有结果数据,才能由外部 函数识别。发送到 Lambda 函数的请求中的参数字段包含数据负载。如果有批处理请求,数据负载中可能会有多个行。以下 Lambda 函数循环访问请求数据负载中的所有行。它还单独迭代单个行中的所有值。

exports.handler = async (event) => { // The 'arguments' field in the request sent to the Lambda function contains the data payload. var t1 = event['arguments']; // 'len(t1)' represents the number of rows in the request payload. // The number of results in the response payload should be the same as the number of rows received. const resp = new Array(t1.length); // Iterating over all the rows in the request payload. for (const [i, x] of t1.entries()) { var sum = 0; // Iterating over all the values in a single row. for (const y of x) { sum = sum + y; } resp[i] = sum; } // The 'results' field should contain the results of the lambda call. const response = { results: resp }; return JSON.stringify(response); };

以下示例使用文本值调用外部函数。

select exfunc_sum(1,2); exfunc_sum --------- 3 (1 row)

以下示例创建一个名为 t_sum 的表,其中包含两个整数数据类型的列 c1 和 c2,并插入两行数据。然后,通过传递此表的列名来调用外部函数。在请求负载的批处理请求中,会将这两个表行作为单个 Lambda 调用发送。

# create table t_sum(c1 int, c2 int); CREATE TABLE # insert into t_sum values (4,5), (6,7); INSERT 0 2 # select exfunc_sum(c1,c2) from t_sum; exfunc_sum --------- 9 13 (2 rows)

使用 Python Lambda 函数的标量 Lambda UDF 示例

以下示例创建一个将数字相乘并返回整数的外部函数。此示例在 Lambda 响应中包含了 success 和 error_msg 字段。当乘法结果中存在整数溢出且 error_msg 消息设置为整数乘溢出时,成功字段设置为 false。

以下示例创建一个名为 exfunc_sum 的外部函数,该函数采用 3 个整数作为输入参数,并返回整数输出。要调用的 Lambda 函数的名称是 lambda_sum。您必须指定 IAM 角色。

create external function exfunc_multiplication(int, int, int) returns int stable LAMBDA 'lambda_multiplication' IAM_ROLE 'arn:aws:iam::123456789012:user/johndoe';

以下示例显示了名为 lambda_multilication 的 AWS Lambda 函数。用于此 Lambda 函数的语言是 Python 3.8。

函数接收请求负载并迭代每一行。Lambda单行中的所有值将相乘以计算该行的结果,该结果将保存在响应列表中。此示例使用默认情况下设置为 true 的布尔成功值。如果行的乘法结果具有整数溢出,则成功值设置为 false。然后,迭代循环中断。

在创建响应负载时,如果成功值为 false,则以下 Lambda 函数会在负载中添加 error_msg 字段,并将错误消息设置为“整数乘积溢出”。如果成功值为 true,则将结果数据添加到结果字段中。结果数组中的行数(如果有)类似于在请求负载中接收的行数。

发送到 Lambda 函数的请求中的参数字段包含数据负载。如果有批处理请求,数据负载中可能会有多个行。以下 Lambda 函数迭代请求数据负载中的所有行,并单独迭代单个行中的所有值。

import json def lambda_handler(event, context): t1 = event['arguments'] # 'len(t1)' represents the number of rows in the request payload. # The number of results in the response payload should be the same as the number of rows received. resp = [None]*len(t1) # By default success is set to 'True'. success = True # Iterating over all rows in the request payload. for i, x in enumerate(t1): mul = 1 # Iterating over all the values in a single row. for j, y in enumerate(x): mul = mul*y # Check integer overflow. if (mul >= 9223372036854775807 or mul <= -9223372036854775808): success = False break else: resp[i] = mul ret = dict() ret['success'] = success if not success: ret['error_msg'] = "Integer multiplication overflow" else: ret['results'] = resp ret_json = json.dumps(ret) return ret_json

以下示例使用文本值调用外部函数。

# select exfunc_multiplication(8, 9, 2); exfunc_multiplication ----------- 144 (1 row)

以下示例创建一个名为 t_multi 的表,其中包含整数数据类型的三列 c1、c2 和 c3。通过传递此表的列名来调用外部函数。数据是以某种方式插入的,以便导致整数溢出以显示如何传播错误。

# create table t_multi (c1 int, c2 int, c3 int); CREATE TABLE # insert into t_multi values (2147483647, 2147483647, 4); INSERT 0 1 # select exfunc_multiplication(c1, c2, c3) from t_multi; ERROR: Integer multiplication overflow DETAIL: ----------------------------------------------- error: Integer multiplication overflow code: 32004 context: query: 38 location: exfunc_data.cpp:276 process: query2_16_38 [pid=30494] -----------------------------------------------