Formats des données d’entrée et de sortie des services à distance

Lorsque Snowflake envoie des données à un service distant ou reçoit des données d’un service distant, les données doivent être formatées correctement. Ce chapitre fournit des informations sur les formats de données appropriés. Les données reçues de Snowflake et renvoyées à Snowflake doivent également être d’un type de données approprié.

Lors de l’exécution d’une fonction externe, par exemple, Snowflake envoie et attend des données dans le format décrit ici. Snowflake envoie les données à un service proxy, et non directement au service distant (pour en savoir plus, voir Introduction aux fonctions externes). Par conséquent, le service proxy doit recevoir (et renvoyer) les données dans un format compatible avec Snowflake. Bien que le service proxy transmette généralement des données inchangées, le proxy peut reformater les données (à la fois en envoi et en réception) pour répondre aux besoins du service distant et de Snowflake.

Par souci de simplicité et pour illustrer les formats que Snowflake s’attend à envoyer et à recevoir, la plupart des exemples de cette section supposent que le service distant lit et écrit des données dans le même format que Snowflake le prévoit et que le service proxy transmet les données sans les modifier dans les deux directions.

Dans ce chapitre :

Format de données envoyé par Snowflake

Chaque requête HTTP de Snowflake est de type POST ou GET.

  • Une requête POST contient des en-têtes et un corps de requête. Le corps de la requête comprend un lot de lignes.

  • Un GET ne contient que des en-têtes, et n’est utilisé que pour le sondage lorsque le service à distance renvoie des résultats de manière asynchrone.

Format du corps

Le corps de la requête POST contient les données, sérialisées au format JSON.

Le schéma pour JSON est :

  • Le niveau supérieur est un objet JSON (un ensemble de paires nom/valeur, également appelé « dictionnaire »).

  • Actuellement, il y a exactement un élément dans cet objet ; la clé de cet élément est nommée « données ».

  • La valeur de cet élément « données » est un tableau JSON, dans lequel :

    • Chaque élément est une ligne de données.

    • Chaque ligne de données est un tableau JSON d’une ou plusieurs colonnes.

    • La première colonne est toujours le numéro de ligne (c’est-à-dire l’index basé sur 0 de la ligne dans le lot).

    • Les colonnes restantes contiennent les arguments de la fonction.

  • Les types de données sont sérialisés comme suit :

    • Les nombres sont sérialisés en tant que nombres JSON.

    • Les booléens sont sérialisés en tant que booléens JSON.

    • Les chaînes sont sérialisées en tant que chaînes JSON.

    • Les variantes sont sérialisées en tant qu’objets JSON.

    • Tous les autres types de données pris en charge sont sérialisés en tant que chaînes JSON.

    • NULL est sérialisé en tant que JSON null.

Pour des exemples d’extraction de données dans un service distant sur chaque plate-forme, voir :

Facultativement, le JSON peut être compressé pour la transmission sur le réseau. La compression est documentée dans CREATE EXTERNAL FUNCTION.

Exemple de corps

Voici un exemple de demande sérialisée pour une fonction externe avec la signature f(integer, varchar, timestamp). Notez que la première colonne est le numéro de ligne dans le lot, et les trois valeurs suivantes sont les arguments de la fonction externe.

{
    "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

Format de l’en-tête

Les informations d’en-tête sont généralement accessibles au service à distance sous la forme d’un ensemble de paires clé/valeur. Les informations d’en-tête comprennent :

  • Les en-têtes HTTP suivants :

    • En-têtes qui décrivent comment les données sont sérialisées dans le corps de la requête :

      • « sf-external-function-format » : ceci est actuellement toujours réglé sur « json ».

      • « sf-external-function-format-version » : ceci est actuellement toujours défini sur « 1.0 ».

    • « sf-external-function-current-query-id » : ceci contient l’ID de requête de la requête qui a appelé cette fonction externe. Vous pouvez l’utiliser pour corréler les requêtes Snowflake aux appels du service distant, par exemple pour aider au débogage des problèmes.

    • « sf-external-function-query-batch-id » : l’ID de lot identifie de manière unique le lot spécifique de lignes traitées avec cette requête. Le service à distance peut utiliser cet ID pour suivre le statut d’un lot en cours de traitement. L” ID peut également être utilisé comme un jeton d’impuissance si les requêtes sont réessayées en raison d’une erreur. L” ID peut également être utilisé pour l’enregistrement et le traçage des demandes par le service à distance.

      L’ID du lot dans un GET est le même que l’ID du lot dans le POST correspondant.

      L” ID de lot est une valeur opaque générée par Snowflake. Le format pourrait changer dans les prochaines versions, les services à distance ne doivent donc pas se fier à un format spécifique ou essayer d’interpréter la valeur.

    • Les en-têtes qui décrivent la signature (nom et types d’arguments) et le type de retour de la fonction externe qui a été appelée dans la requête SQL. Ces valeurs peuvent comporter des caractères qui ne sont pas des caractères standard pour les identificateurs Snowflake, de sorte que les versions de base64 des informations sont incluses, et les caractères non standard sont remplacés par un espace blanc dans les versions hors base64.

      Les en-têtes spécifiques sont les suivants :

      • 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

      Par exemple, les en-têtes envoyés pour la fonction ext_func(n integer)  returns varchar sont :

      • sf-external-function-name : ext_func

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

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

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

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

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

      Notez que parce que les valeurs INTEGER SQL sont traitées comme des NUMBER SQL , l’argument SQL déclaré comme de type INTEGER est décrit comme de type NUMBER.

  • Métadonnées facultatives supplémentaires décrites dans les propriétés « headers » et « context_headers » de CREATE EXTERNAL FUNCTION.

Exemple d’accès à l’en-tête

Pour extraire l’en-tête « sf-external-function-signature » de l’intérieur d’une fonction AWS Lambda écrite en Python, qui reçoit les en-têtes comme un dictionnaire python, exécutez ce qui suit :

def handler(event, context):

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

Les détails seront différents pour d’autres langues et sur d’autres plates-formes Cloud.

Pour les services à distance développés sur AWS, de plus amples informations sur les en-têtes et l’intégration du proxy Lambda sont disponibles dans la documentation AWSAPI Gateway .

Format de données reçu par Snowflake

Format du corps

Lorsqu’un service à distance termine le traitement d’un lot, le service à distance doit renvoyer les données à Snowflake dans un format JSON similaire à celui des données envoyées par Snowflake.

La réponse JSON renvoyée à Snowflake doit contenir une ligne pour chaque ligne envoyée par Snowflake. Chaque ligne renvoyée contient deux valeurs :

  • Le numéro de ligne (c’est-à-dire l’index basé sur 0 de la ligne dans le lot).

  • La valeur renvoyée par la fonction pour cette ligne. La valeur peut être une valeur composée (par exemple, un OBJECT), mais elle doit être exactement une valeur, car toutes les fonctions scalaires Snowflake (externes ou autres) renvoient une seule valeur.

Pour que Snowflake puisse corréler la réponse avec la demande, les numéros de ligne dans les données renvoyées doivent correspondre aux numéros de ligne dans les données envoyées par Snowflake et doivent être renvoyés dans le même ordre qu’ils ont été reçus.

Exemple d’accès au corps

L’exemple JSON suivant montre deux lignes contenant une valeur OBJECT, chacune étant précédée d’un numéro de ligne :

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

Pour composer l’une de ces lignes renvoyées avec Python, vous pouvez utiliser le code suivant :

...
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

Pour accéder à la valeur OBJECT d’une ligne renvoyée avec SQL, utilisez la notation décrite dans Parcours de données semi-structurées. Par exemple :

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

Format de l’en-tête

La réponse peut également contenir les en-têtes HTTP facultatifs suivants :

  • Content-MD5 : Snowflake utilise l’en-tête optionnel Content-MD5 pour vérifier l’intégrité de la réponse. Si cet en-tête est inclus dans la réponse, Snowflake calcule une somme de contrôle MD5 sur le corps de la réponse pour s’assurer qu’il correspond à la somme de contrôle correspondante dans l’en-tête renvoyé. Si les valeurs ne correspondent pas, la requête SQL échoue. La somme de contrôle doit être encodée dans une représentation base64 avant d’être renvoyée dans l’en-tête. Voir l’exemple de code ci-dessous.

Facultativement, le JSON peut être compressé pour la transmission sur le réseau. La compression est documentée dans CREATE EXTERNAL FUNCTION.

Pour plus d’informations sur les délais d’expiration et les tentatives, voir Tenir compte des erreurs d’expiration de délai et Ne supposez pas que le service distant a validé chaque ligne exactement une fois.

Code de statut

La réponse contient également un code de statut HTTP. Snowflake reconnaît les codes de statut HTTP suivants :

Code

Description

200

Traitement par lots réussi.

202

Lot reçu et toujours en cours de traitement.

Les autres valeurs sont traitées comme des erreurs.

Exemple de création de réponse

L’exemple de code Python ci-dessous renvoie une réponse correcte, comprenant le code de réponse HTTP, les données traitées et un en-tête MD5 (qui est facultatif). (Ceci a été écrit en utilisant Python 3.8.)

Cet exemple est basé sur une fonction AWS Lambda. Certains codes peuvent nécessiter une personnalisation pour différentes plates-formes.

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