원격 서비스 데이터용 요청·응답 트랜슬레이터 사용하기
원격 서비스 데이터용 요청·응답 트랜슬레이터 사용하기 (Using request and response translators with data for a remote service)
요청 트랜슬레이터(request translator)와 응답 트랜슬레이터(response translator)를 사용하면 외부 함수가 사용하는 원격 서비스로 보내는 데이터와 그로부터 받는 데이터의 형식을 바꿀 수 있어요. Snowflake 형식과 원격 서비스의 네이티브 형식이 다를 때 이를 중간에서 변환해 주는 역할을 해요.
본문
목적 (Purpose)
Snowflake가 원격 서비스로 데이터를 보낼 때 Snowflake는 정해진 규칙에 따라 데이터를 형식화해요. 마찬가지로 Snowflake가 원격 서비스로부터 데이터를 받을 때도 Snowflake는 같은 규칙에 따라 형식화된 데이터를 기대해요. 많은 원격 서비스는 다른 형식으로 데이터를 처리하길 기대합니다. 요청·응답 트랜슬레이터를 사용하면 편리하게 다음을 수행할 수 있어요:
- 데이터를 Snowflake의 형식에서 원격 서비스의 네이티브 입력 형식으로 변환(요청 트랜슬레이터)
- 데이터를 원격 서비스의 네이티브 출력 형식에서 Snowflake의 형식으로 변환(응답 트랜슬레이터)
SQL 구현 (SQL implementation)
Snowflake의 형식과 원격 서비스의 네이티브 입력 형식 사이에서 데이터를 변환하려면 JavaScript UDF(사용자 정의 함수)를 사용해요. 거의 항상 두 개의 UDF 쌍을 작성합니다: 하나는 요청을 변환하고 하나는 응답을 변환하는 UDF예요.
Snowflake는 각 외부 함수 호출의 일부로 이 함수들을 호출해요. 예를 들어 원격 서비스에 대한 요청의 경우 Snowflake는 요청 트랜슬레이터 함수를 호출하고, Snowflake 형식의 데이터를 전달한 다음, 반환된 데이터를 가져와 원격 서비스로 보내요. 원격 서비스가 데이터를 반환하면 Snowflake는 응답 트랜슬레이터 함수를 호출해 데이터를 Snowflake가 이해하는 형식으로 다시 변환해요.
사용자 관점에서, 트랜슬레이터가 변환 중일 때 외부 함수를 호출하는 것은 트랜슬레이터 없이 외부 함수를 호출하는 것과 같아요. CREATE EXTERNAL FUNCTION 문의 일부로 트랜슬레이터를 지정하면 자동으로 호출돼요.
외부 함수는 한 번에 요청 트랜슬레이터와 응답 트랜슬레이터를 최대 각각 하나씩 가질 수 있어요. 요청·응답 트랜슬레이터 UDF는 보안 UDF(secure UDF)일 수 있어요.
외부 함수에 트랜슬레이터 함수 할당하기 (Assigning a translator function to an external function)
어떤 사용자 정의 함수를 트랜슬레이터로 사용할지 지정하려면 CREATE EXTERNAL FUNCTION 문에 REQUEST_TRANSLATOR와 RESPONSE_TRANSLATOR 절을 포함하세요. 각각은 런타임에 사용할 트랜슬레이터 함수의 이름을 받아요.
예를 들어:
CREATE EXTERNAL FUNCTION f(...)
RETURNS OBJECT
...
REQUEST_TRANSLATOR = my_request_translator_udf
RESPONSE_TRANSLATOR = my_response_translator_udf
...
AS ;
CREATE EXTERNAL FUNCTION 문의 일부로 트랜슬레이터를 지정하는 문법은 다음과 같아요:
CREATE EXTERNAL FUNCTION f(...)
RETURNS OBJECT
...
[ REQUEST_TRANSLATOR = ]
[ RESPONSE_TRANSLATOR = ]
...
여기서:
request_translator_udf_name: 요청 트랜슬레이터 함수의 이름response_translator_udf_name: 응답 트랜슬레이터 함수의 이름
REQUEST_TRANSLATOR와 RESPONSE_TRANSLATOR 파라미터는 각각 타입 OBJECT의 파라미터 하나를 받아요.
ALTER FUNCTION 명령에서도 요청 또는 응답 트랜슬레이터를 지정할 수 있어요. 다음을 할 수 있습니다:
- 외부 함수에 트랜슬레이터가 아직 없으면 추가하기
- 기존 트랜슬레이터 교체하기
- 트랜슬레이터 제거하기
새 트랜슬레이터를 추가하거나 기존 트랜슬레이터를 교체하려면 SET 키워드를 사용하세요.
트랜슬레이터를 추가하거나 교체하려면:
ALTER FUNCTION ...
SET [REQUEST_TRANSLATOR | RESPONSE_TRANSLATOR] = ;
여기서 udf_name은 이전에 만든 JavaScript UDF의 이름이에요.
트랜슬레이터를 제거하려면:
ALTER FUNCTION ...
UNSET [REQUEST_TRANSLATOR | RESPONSE_TRANSLATOR];
SQL 요구 사항 (Requirements for the SQL)
CREATE EXTERNAL FUNCTION또는ALTER FUNCTION문의 트랜슬레이터 함수 이름은 다음 중 하나여야 해요:- 한정된 이름(qualified name, 예:
MyDatabase.MySchema.MyJavaScriptUDF) - 이를 사용하는 외부 함수와 같은 데이터베이스와 스키마에 정의된 이름
- 한정된 이름(qualified name, 예:
- 트랜슬레이터가
CREATE EXTERNAL FUNCTION또는ALTER FUNCTION문에서 지정될 때 트랜슬레이터 UDF는 이미 존재해야 해요. 나중에 UDF를 만들기 위해 이름을 먼저 지정할 수는 없어요(외부 함수를 호출하기 전에 UDF를 만든다고 해도 마찬가지예요). - 트랜슬레이터로 사용되는 UDF는 이를 사용하는 모든 외부 함수에서 제거하지 않고는 삭제(drop)하면 안 돼요. (외부 함수가 호출될 때 트랜슬레이터가 존재하지 않으면 Snowflake는 오류와 함께 실패해요.)
- 트랜슬레이터 UDF가(
ALTER FUNCTION을 통해) 수정된다면 동일한 인터페이스 요구 사항을 유지해야 해요. 인터페이스 요구 사항을 유지하지 않으면 외부 함수를 실행하기 전에 예외가 발생해요.
JavaScript 구현 (JavaScript implementation)
런타임에 SQL은 트랜슬레이터 UDF에 OBJECT를 전달해요. JavaScript 코드는 이를 JavaScript 객체로 받아요.
요청 트랜슬레이터 구현하기 (Implementing a request translator)
요청 트랜슬레이터 입력 속성 (Request translator input properties)
트랜슬레이터 UDF는 event라는 이름의 JavaScript 객체를 받아요. 이 객체는 다음 속성을 포함합니다:
body:data필드의 형식은 기존 Snowflake 행 집합 배치(rowset batch)와 같아요(즉 행들의 배열). 예를 들어:
{
"body": {
"data": [
[0,"cat"],
[1,"dog"]
]
}
}
기존 데이터는 외부 body 아래에 중첩돼 있어요.
serviceUrl: 호출할 외부 함수의 정의된 URL.contextHeaders: 이름이 필드 이름인 모든 컨텍스트 관련 헤더를 포함하는 객체. 예를 들어 객체는 필드 이름SF_CONTEXT_CURRENT_DATABASE를 포함할 수 있고, 해당 값은 현재 데이터베이스 이름을 포함하는 문자열이에요.
요청 트랜슬레이터 출력 속성 (Request translator output properties)
요청 트랜슬레이터는 외부 서비스 API 게이트웨이와 통신하는 데 사용되는 필드를 가진 객체를 반환해요. 그 객체는 세 개의 선택적 필드를 가집니다:
body: 서비스에 전달할 실제 본문을 정의해요. 정의되지 않으면 본문이 없어요.body값은 원격 서비스가 기대하는 형식의 문자열 또는 JSON 객체여야 해요. 값이 문자열이면 그 문자열은 내부 구조를 포함할 수 있어요(예: JSON 호환). 값이 JSON 객체이면 HTTP POST 명령 문자열의 일부로 포함될 수 있도록 문자열로 변환돼요.urlSuffix:serviceUrl값의 끝에 추가되는 서비스 URL의 접미사를 설정해요. 이 접미사에는 쿼리 파라미터도 포함될 수 있어요. 파라미터 이름과 값은 URL 인코딩되어야 해요. 예를 들어a라는 파라미터를my param값으로 설정하려면 공백 문자를 URL 인코딩해야 하므로 파라미터는?a=my%20param이 돼요.translatorData: 요청 트랜슬레이터에서 응답 트랜슬레이터로 전달돼요. 이 필드는 입력 본문, 서비스 URL 또는 접미사, 컨텍스트 헤더 같은 컨텍스트 정보를 전달할 수 있어요.
세 필드 모두 선택 사항이에요. 그러나 실용적으로 대부분의 요청 트랜슬레이터는 적어도 body 데이터를 반환해요.
응답 트랜슬레이터 구현하기 (Implementing a response translator)
응답 트랜슬레이터 입력 속성 (Response translator input properties)
응답 트랜슬레이터 함수의 입력 파라미터는 객체예요. 아래 예시는 두 개의 속성을 포함하는 EVENT를 사용합니다:
body: 외부 서비스 응답에서 디코딩할 응답translatorData: 이 필드가 요청 트랜슬레이터에 의해 반환되면 Snowflake는 이를 응답 트랜슬레이터에 전달해요.
응답 트랜슬레이터 출력 속성 (Response translator output properties)
응답 트랜슬레이터 응답은 body 요소 아래에 객체로 반환되며, 형식은 기존 외부 함수 형식(행들의 배열)이에요. 예를 들어:
{
"body": {
"data": [
[0, "Life"],
[1, "the universe"],
[2, "and everything"]
]
}
}
트랜슬레이터 함수 요구 사항 (Requirements for the translator function)
각 트랜슬레이터 UDF는 다음 요구 사항을 충족해야 해요:
- JavaScript UDF여야 해요.
- 행 배치를 나타내는 타입
OBJECT의 파라미터를 정확히 하나 받아야 해요. - 역시 행 배치를 나타내는 타입
OBJECT의 값을 하나 반환해야 해요. - 스칼라 UDF여야 해요(전달된 각 행(OBJECT)에 대해 하나의 행을 반환). 참고: 트랜슬레이터는 스칼라이지만, 트랜슬레이터에 전달된
OBJECT는 OBJECT 안의 JSON에 여러 행이 내장되어 있을 수 있고(보통 그렇습니다). - 응답 트랜슬레이터 UDF가 반환하는 (OBJECT 안의) 행의 개수와 순서는 요청 트랜슬레이터 UDF에 전달된 (OBJECT 안의) 행의 개수와 순서와 같아야 해요.
예시 요청 트랜슬레이터와 응답 트랜슬레이터 (Example request translator and response translator)
다음 예시는 감정 분석(sentiment analysis)을 수행하는 외부 서비스인 Amazon Comprehend BatchDetectSentiment가 요구하는 형식으로 데이터를 변환하는 데 사용되는 요청 트랜슬레이터와 응답 트랜슬레이터를 보여줘요. 요청 트랜슬레이터는 백엔드 서비스가 기대하는 형식에 맞게 HTTP 요청을 구성해요.
트랜슬레이터를 사용하려면 API 게이트웨이가 필요해요. 이 예시는 이미 감정 분석 서비스와 통신하도록 구성된 API 게이트웨이를 사용해요. AWS 서비스를 백엔드로 통합하는 방법에 대한 자세한 내용은 AWS 문서의 API Gateway 콘솔을 사용한 API 통합 요청 설정(Set up an API integration request)을 참고하세요. 트랜슬레이터를 추가하기 전에 API 통합을 성공적으로 작업하게 만드는 것이 도움이 돼요.
설정 (Setup)
데모 데이터를 보관할 데이터베이스를 설정하세요. 이어서 샘플 UDF(트랜슬레이터)와 외부 함수를 만들면 됩니다.
응답 트랜슬레이터 (Response translator)
응답 트랜슬레이터는:
translatorData배열 길이의 입력 크기로responses라는 배열을 초기화해요. 요청 트랜슬레이터에서 응답 트랜슬레이터로translatorData를 보내 원래 테스트 문자열 목록을 전달했어요.- 오류가 아닌 각 결과를 반복하면서 결과 목록에 넣어요.
- 오류 결과를 반복하면서 결과 목록에 넣어요. 결과 목록에는 어느 항목인지 알려주는 인덱스 위치가 있어요. 생성된 결과의 순서는 입력 순서와 일치해야 해요. 결과 목록에는 감정 정보도 포함돼요.
모든 응답이 모이면 Snowflake가 기대하는 형식의 JSON 본문으로 반환돼요. 다음 직접 테스트는 올바른 형식의 JSON 본문을 반환할 거예요.
SELECT AWSComprehendresponse_translator(
parse_json('{
"translatorData": {
"data": [[0, "I am so happy we got a sunny day for my birthday."],
[1, "$$$$$."],
[2, "Today is my last day in the old house."]]
}
"body": {
"ErrorList": [ { "ErrorCode": 57, "ErrorMessage": "Language unknown", "Index": 1 } ],
"ResultList": [
{ "Index": 0, "Sentiment": "POSITIVE",
"SentimentScore": { "Mixed": 25, "Negative": 5, "Neutral": 1, "Positive": 90 }
},
{ "Index": 2, "Sentiment": "NEGATIVE",
"SentimentScore": { "Mixed": 25, "Negative": 75, "Neutral": 30, "Positive": 20 }
}
]
},
}'
)
);
외부 함수에 트랜슬레이터 할당하기 (Assign the translators to the external function)
외부 함수에 요청 트랜슬레이터와 응답 트랜슬레이터 함수를 request_translator와 response_translator 파라미터의 값으로 함수 이름을 지정해서 추가해요. 이렇게 하면 외부 함수가 실행될 때 자동으로 호출돼요.
CREATE OR REPLACE EXTERNAL FUNCTION ComprehendSentiment(thought varchar)
RETURNS VARIANT
API_INTEGRATION = aws_comprehend_gateway
request_translator = db_name.schema_name.AWSComprehendrequest_translator
response_translator = db_name.schema_name.AWSComprehendresponse_translator
AS 'https://.execute-api.us-east-1.amazonaws.com/test/comprehend_proxy';
함수를 설명(describe)해서 정보를 얻을 수 있어요.
DESCRIBE FUNCTION ComprehendSentiment(VARCHAR);
외부 함수 호출하기 (Call the external function)
단일 문장으로 외부 함수를 호출해서 테스트해 보세요.
SELECT ComprehendSentiment('Today is a good day');
감정 분석 결과가 보일 거예요.
{"Sentiment": "POSITIVE",
"SentimentScore":{"Mixed":0.002436627633869648,
"Negative":0.0014803812373429537,
"Neutral":0.015923455357551575,
"Positive": 0.9801595211029053}}
여러 문장으로 외부 함수를 호출해서 테스트해 보세요. 이전에 만든 것과 같은 demo 테이블을 사용하세요.
SELECT ComprehendSentiment(vc), vc FROM demo;
감정 분석 결과가 표시돼요. 외부 함수가 호출될 때 요청 트랜슬레이터가 자동으로 데이터를 외부 서비스가 요구하는 형식으로 변환했어요. 그런 다음 응답 트랜슬레이터가 외부 서비스의 응답을 자동으로 Snowflake가 요구하는 형식으로 다시 변환했어요.
요청·응답 트랜슬레이터 테스트 팁 (Tips for testing request and response translators)
- 테스트 케이스 값은 일반적으로
OBJECT값(키-값 쌍의 모음)이에요. 이 값들은 이 문서의 규칙의 요구 사항을 충족하도록 형식화되어야 해요. - 문자열로 변환된 예시 입력을 전달해서 요청 트랜슬레이터 또는 응답 트랜슬레이터 테스트를 시작할 수 있어요. 예를 들어:
select my_request_translator_function(parse_json('{"body": {"data": [ [0,"cat",867], [1,"dog",5309] ] } }'));
(PARSE_JSON()의 입력은 JSON 형식의 문자열이어야 해요.)
- 적절하다면
NULL값으로 테스트하세요. 테스트 케이스에 SQLNULL값을 하나 이상 포함하세요. - 테스트 케이스에 JSON
NULL값을 하나 이상 포함하세요. - 요청을 변환하는 것과 응답을 변환하는 것은 종종 역 과정(converse)이에요. 개념적으로:
my_response_translator_udf(my_request_translator_udf(x)) = x
데이터 형식이 일치한다면 이 특성을 사용해 요청 트랜슬레이터와 응답 트랜슬레이터를 테스트하는 데 도움을 얻을 수 있어요. 좋은 테스트 값이 있는 테이블을 만든 다음 다음과 유사한 명령을 실행하세요:
SELECT test_case_column
FROM test_table
WHERE my_response_translator_udf(my_request_translator_udf(x)) != x;
이 쿼리는 어떤 행도 반환하지 않아야 해요. 참고: 요청을 변환하는 것과 응답을 변환하는 것이 항상 정확히 역 과정은 아니에요. 역 과정이 아닐 수 있는 예시는 TO_JSON() 함수 문서의 "Usage Notes" 섹션에서 역 함수(converse functions)에 대한 논의를 참고하세요.
더 알아보기 (Learn more)
- 외부 함수 소개 (external-functions-introduction)
- 고성능 외부 함수 설계 (external-functions-implementation)
- 원격 서비스 입출력 데이터 형식 (external-functions-data-format)
- 외부 함수 보안 (external-functions-security)