CREATE EXTERNAL FUNCTION
Amazon Redshift에 대해 AWS Lambda를 기반으로 스칼라 사용자 정의 함수(UDF)를 생성합니다. Lambda 사용자 정의 함수에 대한 자세한 내용은 Scalar Lambda UDF 섹션을 참조하세요.
필수 권한
CREATE EXTERNAL FUNCTION에 필요한 권한은 다음과 같습니다.
수퍼유저
CREATE [ OR REPLACE ] EXTERNAL FUNCTION 권한이 있는 사용자
구문
CREATE [ OR REPLACE ] EXTERNAL FUNCTION external_fn_name ( [data_type] [, ...] ) RETURNS data_type { VOLATILE | STABLE } LAMBDA 'lambda_fn_name' IAM_ROLE { default | ‘arn:aws:iam::
<AWS 계정-id>
:role/<role-name>
’ RETRY_TIMEOUT milliseconds MAX_BATCH_ROWS count MAX_BATCH_SIZE size [ KB | MB ];
파라미터
- OR REPLACE
-
이름 및 입력 인수 데이터 형식이 같은 함수 또는 서명이 같은 함수인 경우 이런 함수가 이미 하나 존재하므로 기존 함수를 대체하도록 지정하는 절입니다. 함수는 똑같은 데이터 형식 집합을 정의하는 새 함수로만 바꿀 수 있습니다. 수퍼유저만이 함수를 바꿀 수 있습니다.
기존 함수와 이름은 같지만 서명이 다른 함수를 정의하면 새 함수가 생성됩니다. 즉, 함수 이름이 오버로드됩니다. 자세한 내용은 함수 이름 오버로드 단원을 참조하십시오.
- external_fn_name
-
외부 함수의 이름입니다. 스키마 이름을 지정하는 경우(예: myschema.myfunction) 함수는 지정된 스키마를 사용하여 생성됩니다. 그렇지 않으면, 함수가 현재 스키마로 생성됩니다. 유효한 이름에 대한 자세한 내용은 이름 및 식별자 섹션을 참조하세요.
모든 UDF 이름에
f_
를 접두사로 사용하는 것이 좋습니다. Amazon Redshift는 UDF 이름용으로f_
접두사를 예약합니다.f_
접두사를 사용하면 UDF 이름이 현재 또는 미래에 Amazon Redshift의 기본 제공 SQL 함수 이름과 충돌하지 않도록 할 수 있습니다. 자세한 내용은 UDF 이름 충돌 방지 단원을 참조하십시오. - data_type
-
입력 인수의 데이터 형식입니다. 자세한 내용은 데이터 타입 단원을 참조하십시오.
- RETURNS data_type
-
함수에 의해 반환되는 값의 데이터 형식입니다. RETURNS 데이터 형식은 임의의 표준 Amazon Redshift 데이터 형식일 수 있습니다. 자세한 내용은 Python UDF 데이터 형식 단원을 참조하십시오.
- VOLATILE | STABLE
-
쿼리 최적화 프로그램에 함수의 휘발성에 대해 알립니다.
최상으로 최적화하기 위해 함수에 대해 유효한 가장 엄격한 휘발성 범주로 함수에 레이블을 지정합니다. 가장 덜 엄격한 범주부터 시작해서 엄격성의 순으로 휘발성 범주를 나열하면 다음과 같습니다.
-
VOLATILE
-
STABLE
VOLATILE
인수가 같을 경우, 함수는 단일 명령문의 행에 대해서도 연속적인 호출에 대해 상이한 결과를 반환할 수 있습니다. 쿼리 옵티마이저는 휘발성 함수의 동작에 대해 가정을 할 수 없습니다. 휘발성 함수를 사용하는 쿼리는 모든 입력에 대해 함수를 재평가해야 합니다.
STABLE
인수가 동일하면 함수는 단일 문 내에서 처리되는 연속적인 호출에서 동일한 결과를 반환하도록 보장됩니다. 이 함수는 서로 다른 명령문에서 호출될 경우 서로 다른 결과를 반환할 수 있습니다. 이 범주를 사용하면 옵티마이저가 단일 문 내에서 함수가 호출되는 횟수를 줄일 수 있습니다.
선택한 엄격도가 함수에 유효하지 않은 경우 옵티마이저가 이 엄격도에 따라 일부 호출을 건너뛸 수 있다는 점에 유의하세요. 이로 인해 잘못된 결과 집합이 생성될 수 있습니다.
IMMUTABLE 절은 현재 Lambda UDF에서 지원되지 않습니다.
-
- LAMBDA 'lambda_fn_name'
-
Amazon Redshift에서 호출하는 함수의 이름입니다.
AWS Lambda 함수를 생성하는 단계는 AWS Lambda 개발자 안내서의 콘솔로 Lambda 함수 생성 섹션을 참조하세요.
Lambda 함수에 필요한 권한에 대한 자세한 내용은 AWS Lambda 개발자 안내서의 AWS Lambda 권한 섹션을 참조하세요.
- IAM_ROLE { default | ‘arn:aws:iam::
<AWS 계정-id>
:role/<role-name>
’ -
기본 키워드를 사용하여 CREATE EXTERNAL FUNCTION 명령이 실행될 때 Amazon Redshift에서 기본값으로 설정되고 클러스터와 연결된 IAM 역할을 사용하도록 합니다.
클러스터가 인증 및 권한 부여에 사용하는 IAM 역할의 Amazon 리소스 이름(ARN)을 사용합니다. CREATE EXTERNAL FUNCTION 명령은 이 IAM 역할을 통해 Lambda 함수를 호출할 권한이 있습니다. 클러스터에 연결된 Lambda 함수를 호출할 수 있는 권한이 있는 기존 IAM 역할이 있는 경우 역할의 ARN을 대체할 수 있습니다. 자세한 내용은 Lambda UDF에 대한 권한 부여 파라미터 구성 단원을 참조하십시오.
다음은 IAM_ROLE 파라미터에 대한 구문을 나타낸 것입니다.
IAM_ROLE 'arn:aws:iam::aws-account-id:role/role-name'
- RETRY_TIMEOUT milliseconds
-
Amazon Redshift가 재시도 백오프 지연에 사용하는 총 시간(밀리초)입니다.
실패한 쿼리에 대해 즉시 재시도하는 대신 Amazon Redshift는 백오프를 수행하고 재시도 사이에 일정 시간 동안 기다립니다. 그런 다음 Amazon Redshift는 모든 지연의 합계가 지정한 RETRY_TIMEOUT 값과 같거나 초과할 때까지 실패한 쿼리를 다시 실행하도록 요청을 재시도합니다. 기본값은 20,000밀리초입니다.
Lambda 함수가 호출되면 Amazon Redshift는
TooManyRequestsException
,EC2ThrottledException
,ServiceException
등의 오류를 수신하는 쿼리에 대해 재시도합니다.RETRY_TIMEOUT 파라미터를 0밀리초로 설정하여 Lambda UDF에 대한 재시도를 방지할 수 있습니다.
- MAX_BATCH_ROWS count
-
Amazon Redshift가 단일 람다 호출에 대한 단일 배치 요청으로 보내는 최대 행 수입니다.
이 파라미터의 최소값은 1입니다. 최대값은 INT_MAX 또는 2,147,483,647입니다.
이 파라미터는 선택 사항입니다. 기본값은 INT_MAX 또는 2,147,483,647입니다.
- MAX_BATCH_SIZE size[KB|MB]
-
Amazon Redshift가 단일 람다 호출에 대한 단일 배치 요청으로 보내는 데이터 페이로드의 최대 크기입니다.
이 파라미터의 최소값은 1KB입니다. 최대값은 5MB입니다.
이 파라미터의 기본값은 5MB입니다.
KB 및 MB는 선택 사항입니다. 측정 단위를 설정하지 않으면 Amazon Redshift는 기본적으로 KB를 사용합니다.
사용 노트
Lambda UDF를 생성할 때 다음 사항을 고려하세요.
입력 인수에 대한 Lambda 함수 호출 순서는 고정되거나 보장되지 않습니다. 클러스터 구성에 따라 쿼리를 실행하는 인스턴스마다 다를 수 있습니다.
함수는 각 입력 인수에 한 번만 적용된다는 보장이 없습니다. Amazon Redshift와 AWS Lambda 간의 상호 작용으로 인해 동일한 입력으로 반복적인 호출이 발생할 수 있습니다.
예시
다음은 스칼라 Lambda 사용자 정의 함수(UDF)를 사용하는 예입니다.
Node.js Lambda 함수를 사용하는 스칼라 Lambda UDF 예
다음 예에서는 2개의 정수를 입력 인수로 사용하는 exfunc_sum
이라는 외부 함수를 생성합니다. 이 함수는 정수 출력으로 합계를 반환합니다. 호출할 Lambda 함수의 이름은 lambda_sum
입니다. 이 Lambda 함수에 사용되는 언어는 Node.js 12.x입니다. IAM 역할을 지정해야 합니다. 이 예에서는 'arn:aws:iam::123456789012:user/johndoe'
를 IAM 역할로 사용합니다.
CREATE EXTERNAL FUNCTION exfunc_sum(INT,INT) RETURNS INT VOLATILE LAMBDA 'lambda_sum' IAM_ROLE 'arn:aws:iam::123456789012:role/Redshift-Exfunc-Test';
Lambda 함수는 요청 페이로드를 받아 각 행을 반복합니다. 단일 행의 모든 값은 응답 배열에 저장되는 해당 행의 합계를 계산하기 위해 추가됩니다. 결과 배열의 행 수는 요청 페이로드에서 수신된 행 수와 유사합니다.
JSON 응답 페이로드는 'results' 필드에 결과 데이터가 있어야 외부 기능에서 인식됩니다. Lambda 함수로 전송된 요청의 arguments 필드에는 데이터 페이로드가 포함되어 있습니다. 배치 요청의 경우 데이터 페이로드에 여러 행이 있을 수 있습니다. 다음 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)
다음 예에서는 정수 데이터 형식의 두 열 c1 및 c2가 있는 t_sum이라는 테이블을 생성하고 두 행의 데이터를 삽입합니다. 그런 다음 이 테이블의 열 이름을 전달하여 외부 함수를 호출합니다. 두 테이블 행은 단일 Lambda 호출로 요청 페이로드의 배치 요청으로 전송됩니다.
CREATE TABLE t_sum(c1 int, c2 int); INSERT INTO t_sum VALUES (4,5), (6,7); SELECT exfunc_sum(c1,c2) FROM t_sum; exfunc_sum --------------- 9 13 (2 rows)
RETRY_TIMEOUT 속성을 사용하는 Scalar Lambda UDF 예
다음 섹션에서 Lambda UDF에서 RETRY_TIMEOUT 속성을 사용하는 방법의 예를 찾아볼 수 있습니다.
AWS Lambda 함수에는 각 함수에 대해 설정할 수 있는 동시성 제한이 있습니다. 동시성 한도에 대한 자세한 내용은 AWS Lambda개발자 가이드의 Lambda 함수에 대한 동시성 관리 및 AWS 컴퓨팅 블로그의 게시물 AWS Lambda 함수 동시성 관리
Lambda UDF에서 제공하는 요청 수가 동시성 제한을 초과하면 새 요청에서 TooManyRequestsException
오류를 수신합니다. ambda UDF는 Lambda 함수로 전송된 요청 간의 모든 지연 합계가 설정한 RETRY_TIMEOUT 값과 같거나 초과할 때까지 이 오류에 대해 재시도합니다. 기본 RETRY_TIMEOUT 값은 20,000밀리초입니다.
다음 예시에서는 exfunc_sleep_3
이라는 Lambda 함수를 생성합니다. 이 함수는 요청 페이로드를 받아 각 행을 반복하고 입력을 대문자로 변환합니다. 그런 다음 3초 동안 휴면하고 결과를 반환합니다. 이 Lambda 함수에 사용되는 언어는 Python 3.8입니다.
결과 배열의 행 수는 요청 페이로드에서 수신된 행 수와 유사합니다. JSON 응답 페이로드는 results
필드에 결과 데이터가 있어야 외부 기능에서 인식됩니다. Lambda 함수로 전송된 요청의 arguments
필드에는 데이터 페이로드가 포함되어 있습니다. 배치 요청의 경우 데이터 페이로드에 여러 행이 나타날 수 있습니다.
이 함수의 동시성 제한은 RETRY_TIMEOUT 속성의 사용을 보여주기 위해 예약된 동시성에서 특별히 1로 설정됩니다. 속성이 1로 설정되면 Lambda 함수는 한 번에 하나의 요청만 처리할 수 있습니다.
import json import time 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) # Iterating over all rows in the request payload. for i, x in enumerate(t1): # Iterating over all the values in a single row. for j, y in enumerate(x): resp[i] = y.upper() time.sleep(3) ret = dict() ret['results'] = resp ret_json = json.dumps(ret) return ret_json
다음 두 가지 추가 예에서는 RETRY_TIMEOUT 속성을 보여줍니다. 각 예에서 단일 Lambda UDF를 호출합니다. Lambda UDF를 호출하는 동안 각 예에서는 동일한 SQL 쿼리를 실행하여 동시에 2개의 동시 데이터베이스 세션에서 Lambda UDF를 호출합니다. Lambda UDF를 호출하는 첫 번째 쿼리가 UDF에 의해 제공되는 경우 두 번째 쿼리는 TooManyRequestsException
오류를 수신합니다. 이 결과는 UDF에서 예약된 동시성을 1로 특별히 설정했기 때문에 발생합니다. Lambda 함수에 대해 예약된 동시성을 설정하는 방법에 대한 자세한 내용은 예약된 동시성 구성 섹션을 참조하세요.
다음 첫 번째 예에서는 Lambda UDF의 RETRY_TIMEOUT 속성을 0밀리초로 설정합니다. Lambda 요청이 Lambda 함수에서 예외를 수신하면 Amazon Redshift는 재시도하지 않습니다. RETRY_TIMEOUT 특성이 0으로 설정되어 있기 때문에 이러한 결과가 발생합니다.
CREATE OR REPLACE EXTERNAL FUNCTION exfunc_upper(varchar) RETURNS varchar VOLATILE LAMBDA 'exfunc_sleep_3' IAM_ROLE 'arn:aws:iam::123456789012:role/Redshift-Exfunc-Test' RETRY_TIMEOUT 0;
RETRY_TIMEOUT을 0으로 설정하면 별도의 데이터베이스 세션에서 다음 두 쿼리를 실행하여 다른 결과를 볼 수 있습니다.
Lambda UDF를 사용하는 첫 번째 SQL 쿼리가 성공적으로 실행됩니다.
select exfunc_upper('Varchar'); exfunc_upper -------------- VARCHAR (1 row)
별도의 데이터베이스 세션에서 동시에 실행되는 두 번째 쿼리는 TooManyRequestsException
오류를 수신합니다.
select exfunc_upper('Varchar'); ERROR: Rate Exceeded.; Exception: TooManyRequestsException; ShouldRetry: 1 DETAIL: ----------------------------------------------- error: Rate Exceeded.; Exception: TooManyRequestsException; ShouldRetry: 1 code: 32103 context:query: 0 location: exfunc_client.cpp:102 process: padbmaster [pid=26384] -----------------------------------------------
다음 두 번째 예에서는 Lambda UDF의 RETRY_TIMEOUT 속성을 3,000밀리초로 설정합니다. 두 번째 쿼리가 동시에 실행되더라도 총 지연 시간이 3,000밀리초가 될 때까지 Lambda UDF가 재시도합니다. 따라서 두 쿼리가 모두 성공적으로 실행됩니다.
CREATE OR REPLACE EXTERNAL FUNCTION exfunc_upper(varchar) RETURNS varchar VOLATILE LAMBDA 'exfunc_sleep_3' IAM_ROLE 'arn:aws:iam::123456789012:role/Redshift-Exfunc-Test' RETRY_TIMEOUT 3000;
RETRY_TIMEOUT을 3,000밀리초로 설정하면 별도의 데이터베이스 세션에서 다음 두 쿼리를 실행하여 같은 결과를 볼 수 있습니다.
Lambda UDF를 실행하는 첫 번째 SQL 쿼리가 성공적으로 실행됩니다.
select exfunc_upper('Varchar'); exfunc_upper -------------- VARCHAR (1 row)
두 번째 쿼리가 동시에 실행되고 총 지연 시간이 3,000밀리초가 될 때까지 Lambda UDF가 재시도합니다.
select exfunc_upper('Varchar'); exfunc_upper -------------- VARCHAR (1 row)
Python Lambda 함수를 사용하는 스칼라 Lambda UDF 예
다음 예에서는 exfunc_multiplication
이라는 외부 함수를 생성하고 숫자를 곱하고 정수를 반환합니다. 이 예에서는 Lambda 응답에 성공 및 error_msg
필드를 통합합니다. 곱셈 결과에 정수 오버플로가 있는 경우 성공 필드가 false로 설정되고 error_msg
메시지가 Integer multiplication overflow
로 설정됩니다. exfunc_multiplication
함수는 3개의 정수를 입력 인수로 사용하고 합계를 정수 출력으로 반환합니다.
호출되는 Lambda 함수의 이름은 lambda_multiplication
입니다. 이 Lambda 함수에 사용되는 언어는 Python 3.8입니다. IAM 역할을 지정해야 합니다.
CREATE EXTERNAL FUNCTION exfunc_multiplication(int, int, int) RETURNS INT VOLATILE LAMBDA 'lambda_multiplication' IAM_ROLE 'arn:aws:iam::123456789012:role/Redshift-Exfunc-Test';
Lambda 함수는 요청 페이로드를 받아 각 행을 반복합니다. 단일 행의 모든 값을 곱하여 응답 목록에 저장되는 해당 행의 결과를 계산합니다. 이 예에서는 기본적으로 true로 설정된 부울 성공 값을 사용합니다. 행의 곱셈 결과에 정수 오버플로가 있으면 성공 값은 false로 설정됩니다. 그런 다음 반복 루프가 중단됩니다.
응답 페이로드를 생성하는 동안 성공 값이 false인 경우 다음 Lambda 함수는 페이로드에 error_msg
필드를 추가합니다. 또한 오류 메시지를 Integer multiplication overflow
로 설정합니다. 성공 값이 true이면 결과 필드에 결과 데이터가 추가됩니다. 결과 배열(있는 경우)의 행 수는 요청 페이로드에서 수신된 행 수와 유사합니다.
Lambda 함수로 전송된 요청의 arguments 필드에는 데이터 페이로드가 포함되어 있습니다. 배치 요청의 경우 데이터 페이로드에 여러 행이 있을 수 있습니다. 다음 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)
다음 예에서는 3개(c1, c2, c3)의 정수 데이터 형식 열이 있는 t_multi라는 테이블을 생성합니다. 이 테이블의 열 이름을 전달하여 외부 함수를 호출합니다. 정수 오버플로가 오류 전파 방식을 표시하는 방식으로 데이터가 삽입됩니다.
CREATE TABLE t_multi (c1 int, c2 int, c3 int); INSERT INTO t_multi VALUES (2147483647, 2147483647, 4); SELECT exfunc_multiplication(c1, c2, c3) FROM t_multi; DETAIL: ----------------------------------------------- error: Integer multiplication overflow code: 32004context: context: query: 38 location: exfunc_data.cpp:276 process: query2_16_38 [pid=30494] -----------------------------------------------