원격 서비스 입력 및 출력 데이터 타입

Snowflake가 원격 서비스로 데이터를 보내거나 원격 서비스에서 데이터를 수신할 때, 데이터 타입이 올바르게 지정되어야 합니다. 이 항목에서는 올바른 데이터 타입에 대한 정보를 제공합니다. Snowflake에서 수신되는 데이터와 Snowflake로 반환되는 데이터도 적절한 데이터 타입 이어야 합니다.

예를 들어, 외부 함수를 실행할 때 Snowflake는 여기에 설명된 타입으로 데이터를 전송하고 이 타입이 필요합니다. 원격 서비스로 직접 전송하는 것이 아닌 프록시 서비스로 데이터를 전송합니다(자세한 내용은 외부 함수 소개 참조). 따라서 프록시 서비스는 Snowflake 호환 형식으로 데이터를 수신하고 반환해야 합니다. 일반적으로 프록시 서비스는 변경되지 않은 상태로 데이터를 전달하지만, 프록시는 원격 서비스와 Snowflake 모두의 필요를 충족하도록 데이터의 형식을 다시 지정할 수 있습니다(전송과 수신 모두).

단순성을 위해서나 Snowflake가 보내고 받을 것으로 예상하는 형식을 설명하는 데 도움이 될 목적을 위해서나, 이 섹션에서 드는 예에서는 대부분 원격 서비스가 Snowflake에서 예상하는 것과 같은 형식의 데이터를 읽고 쓰며 프록시 서비스가 데이터를 변경되지 않은 상태로 양방향으로 전달한다고 가정합니다.

이 항목의 내용:

Snowflake에서 보내는 데이터 타입

Snowflake의 각 HTTP 요청은 POST 또는 GET입니다.

  • POST 요청은 헤더와 요청 본문을 포함합니다. 요청 본문은 행 배치 를 포함합니다.

  • GET은 헤더만 포함하며, 원격 서비스가 결과를 비동기로 반환할 때 폴링에만 사용됩니다.

본문 형식

POST 요청의 본문에는 JSON 형식으로 직렬화된 데이터가 포함됩니다.

JSON의 스키마는 다음과 같습니다.

  • 최상위 수준은 JSON 오브젝트(《사전》이라고도 하는 이름/값 쌍 세트)입니다.

  • 현재, 그 오브젝트에는 정확히 한 개의 항목이 있고, 그 항목의 키 이름은 《data》입니다.

  • 그 《data》 항목의 값은 JSON 배열이며, 여기서

    • 각 요소는 1개의 데이터 열입니다.

    • 데이터의 각 행은 하나 이상의 열로 구성된 JSON 배열입니다.

    • 첫 번째 열은 항상 행 번호입니다(즉, 배치 내부에 있는 행의 0부터 시작하는 인덱스).

    • 나머지 열에는 함수에 대한 인자가 포함됩니다.

  • 데이터 타입은 다음과 같이 직렬화됩니다.

    • 숫자는 JSON 숫자로 직렬화됩니다.

    • 부울은 JSON 부울로 직렬화됩니다.

    • 문자열은 JSON 문자열로 직렬화됩니다.

    • 오브젝트는 JSON 오브젝트로 직렬화됩니다.

    • 지원되는 다른 모든 데이터 타입은 JSON 문자열로 직렬화됩니다.

    • NULL은 JSON null로 직렬화됩니다.

각 플랫폼의 원격 서비스에서 데이터를 추출하는 예는 다음을 참조하십시오.

선택적으로, 네트워크를 통해 전송하기 위해 JSON을 압축할 수 있습니다. 압축은 CREATE EXTERNAL FUNCTION 에 설명되어 있습니다.

본문의 예

다음은 서명 f(integer, varchar, timestamp) 가 있는 외부 함수에 대해 직렬화된 요청의 예입니다. 첫 번째 열은 배치 내의 행 번호이고, 이후 3개의 값은 외부 함수에 대한 인자입니다.

{
    "data": [
                [0, 10, "Alex", "2014-01-01 16:00:00"],
                [1, 20, "Steve", "2015-01-01 16:00:00"],
                [2, 30, "Alice", "2016-01-01 16:00:00"],
                [3, 40, "Adrian", "2017-01-01 16:00:00"]
            ]
}
Copy

헤더 형식

헤더 정보는 일반적으로 원격 서비스에서 키/값 쌍의 세트로 사용할 수 있습니다. 헤더 정보는 다음을 포함합니다.

  • 다음과 같은 HTTP 헤더:

    • 요청 본문에서 데이터가 직렬화되는 방식을 설명하는 헤더:

      • 《sf-external-function-format》: 현재 항상 《json》으로 설정됩니다.

      • 《sf-external-function-format-version》: 현재 항상 《1.0》으로 설정됩니다.

    • 《sf-external-function-current-query-id》: 이 외부 함수를 호출한 쿼리의 쿼리 ID를 포함합니다. 예컨대 문제를 디버그하는 데 도움이 되도록, 이를 사용해 Snowflake 쿼리를 원격 서비스의 호출과 연관시킬 수 있습니다.

    • 《sf-external-function-query-batch-id》: 배치 ID는 이 요청으로 처리한 행의 특정 배치를 고유하게 식별합니다. 원격 서비스는 이 ID를 사용하여 처리 중인 배치의 상태를 추적할 수 있습니다. 이 ID는 오류로 인해 요청을 다시 시도하는 경우 멱등성 토큰으로 사용할 수도 있습니다. 또한, 원격 서비스에서 요청의 기록/추적에 이 ID를 사용할 수도 있습니다.

      GET의 배치 ID는 해당 POST의 배치 ID와 똑같습니다.

      배치 ID는 Snowflake에서 생성되는 불투명 값입니다. 형식은 향후 릴리스에서 변경될 수 있으므로, 원격 서비스는 특정 형식에 의존하거나 값을 해석하려고 하면 안 됩니다.

    • SQL 쿼리에서 호출된 외부 함수의 서명(이름 및 인자 형식)과 반환 형식을 설명하는 헤더입니다. 이러한 값은 Snowflake 식별자 에 대한 비표준 문자가 있을 수 있으므로 base64 버전의 정보가 포함되며, 비표준 문자는 base64 이외의 버전에서 공백으로 바뀝니다.

      특정 헤더는 다음과 같습니다.

      • sf-external-function-name

      • sf-external-function-name-base64

      • sf-external-function-signature

      • sf-external-function-signature-base64

      • sf-external-function-return-type

      • sf-external-function-return-type-base64

      예를 들어, 함수 ext_func(n integer)  returns varchar 를 위해 전송된 헤더는 다음과 같습니다.

      • sf-external-function-name: ext_func

      • sf-external-function-name-base64: <base64 값>

      • sf-external-function-signature: (N NUMBER)

      • sf-external-function-signature-base64: <base64 값>

      • sf-external-function-return-type: VARCHAR(16777216)

      • sf-external-function-return-type-base64: <base64 값>

      SQL INTEGER 값은 SQL NUMBER로 처리되므로, INTEGER 형식으로 선언된 SQL 인자는 NUMBER 형식으로 설명됩니다.

  • CREATE EXTERNAL FUNCTION 의 《headers》 및 《context_headers》 속성에 설명된 추가 옵션 메타데이터입니다.

헤더 액세스 예

Python 딕셔너리로 헤더를 수신하도록 Python으로 작성된 AWS Lambda Function 내부에서 《sf-external-function-signature》 헤더를 추출하려면 다음을 실행하십시오.

def handler(event, context):

    request_headers = event["headers"]
    signature = request_headers["sf-external-function-signature"]
Copy

다른 언어와 다른 클라우드 플랫폼에서 이 세부 정보는 다릅니다.

AWS에서 개발된 원격 서비스의 경우, 헤더와 람다 프록시 통합에 대한 자세한 내용은 AWSAPI Gateway 설명서 에서 확인할 수 있습니다.

Snowflake에서 받는 데이터 타입

본문 형식

원격 서비스가 배치 처리를 마치면 원격 서비스가 Snowflake에서 보낸 데이터의 형식과 유사한 JSON 형식으로 데이터를 Snowflake로 다시 보내야 합니다.

Snowflake로 반환되는 JSON 응답에는 Snowflake에서 보내는 행마다 한 개의 행이 포함되어야 합니다. 반환되는 각 행에 다음 두 개의 값이 포함됩니다.

  • 행 번호(즉, 배치 내부에 있는 행의 0부터 시작하는 인덱스).

  • 그 행에 대해 함수에서 반환된 값. 이 값은 복합 값(예: OBJECT)일 수 있지만, 모든 스칼라 Snowflake 함수(외부 또는 그 밖의 함수)는 단일 값을 반환하므로 정확히 1개의 값이어야 합니다.

Snowflake가 응답을 요청과 연결할 수 있으려면, 반환된 데이터의 행 번호가 Snowflake가 보낸 데이터의 행 번호와 일치하고 수신된 순서와 같은 순서로 반환되어야 합니다.

본문의 액세스 예

다음 JSON 예는 OBJECT 값이 포함되고 각 행 앞에 행 번호가 오는 행 2개를 보여줍니다.

{
    "data":
        [
            [ 0, { "City" : "Warsaw",  "latitude" : 52.23, "longitude" :  21.01 } ],
            [ 1, { "City" : "Toronto", "latitude" : 43.65, "longitude" : -79.38 } ]
        ]
}
Copy

Python으로 이러한 반환된 행 중 하나를 작성하려면 다음 코드를 사용할 수 있습니다.

...
row_number = 0
output_value = {}

output_value["city"] = "Warsaw"
output_value["latitude"] = 21.01
output_value["longitude"] = 52.23
row_to_return = [row_number, output_value]
...
Copy

SQL을 통해 반환된 행의 OBJECT 값에 액세스하려면 반정형 데이터 탐색하기 에 설명되는 표기법을 사용합니다. 예:

select val:city, val:latitude, val:longitude
    from (select ext_func_city_lat_long(city_name) as val from table_of_city_names);
Copy

헤더 형식

응답에는 다음과 같은 선택적 HTTP 헤더도 포함될 수 있습니다.

  • Content-MD5: Snowflake는 선택적 Content-MD5 헤더를 사용하여 응답의 무결성을 확인합니다. 이 헤더가 응답에 포함된 경우 Snowflake는 응답 본문의 MD5 체크섬을 계산하여 반환된 헤더의 해당 체크섬과 일치하는지 확인합니다. 값이 일치하지 않으면 SQL 쿼리가 실패합니다. 체크섬은 헤더에서 반환되기 전에 base64 표현으로 인코딩해야 합니다. 아래 예시 코드를 참조하십시오.

선택적으로, 네트워크를 통해 전송하기 위해 JSON을 압축할 수 있습니다. 압축은 CREATE EXTERNAL FUNCTION 에 설명되어 있습니다.

시간 제한 및 재시도에 대한 자세한 내용은 시간 제한 오류에 대한 설명원격 서비스가 행마다 정확히 한 번만 전달된다고 가정하지 않기 를 참조하십시오.

상태 코드

응답에는 HTTP 상태 코드도 포함됩니다. Snowflake는 다음 HTTP 상태 코드를 인식합니다.

코드

설명

200

배치를 성공적으로 처리했습니다.

202

배치를 받아 아직 처리 중입니다.

다른 값은 오류로 처리됩니다.

응답 생성 예

아래의 예시 Python 코드는 HTTP 응답 코드, 처리된 데이터, MD5 헤더(선택 사항)를 포함하여 적절한 응답을 반환합니다. (이 코드는 Python 3.8을 사용해 작성했습니다.)

이 예는 AWS Lambda Function을 기반으로 합니다. 어떤 코드는 다른 플랫폼을 위해 사용자 지정이 필요할 수 있습니다.

import json
import hashlib
import base64

def handler(event, context):

    # The return value should contain an array of arrays (one inner array
    # per input row for a scalar function).
    array_of_rows_to_return = [ ]

    ...

    json_compatible_string_to_return = json.dumps({"data" : array_of_rows_to_return})

    # Calculate MD5 checksum for the response
    md5digest = hashlib.md5(json_compatible_string_to_return.encode('utf-8')).digest()
    response_headers = {
        'Content-MD5' : base64.b64encode(md5digest)
    }

    # Return the HTTP status code, the processed data, and the headers
    # (including the Content-MD5 header).
    return {
        'statusCode': 200,
        'body': json_compatible_string_to_return,
        'headers': response_headers
    }
Copy