Eingabe- und Ausgabedatenformate von Remotediensten

Wenn Snowflake Daten an einen Remotedienst sendet oder Daten von einem Remotedienst empfängt, müssen die Daten korrekt formatiert werden. Unter diesem Thema finden Sie Informationen zu den richtigen Datenformaten. Daten, die von Snowflake empfangen und an Snowflake zurückgegeben werden, müssen ebenfalls einen geeigneten Datentyp haben.

Beim Ausführen einer externen Funktion beispielsweise sendet Snowflake Daten in dem hier beschriebenen Format und erwartet sie auch so wieder zurück. Snowflake sendet die Daten an einen Proxydienst und nicht direkt an den Remotedienst (mehr dazu siehe Einführung in externe Funktionen). Daher muss der Proxydienst Daten in einem Snowflake-kompatiblen Format empfangen (und zurückgeben). Obwohl der Proxydienst normalerweise Daten unverändert weiterleitet, kann der Proxy zu sendende und zu empfangende Daten neu formatieren, um die Anforderungen sowohl des Remotedienstes als auch von Snowflake zu erfüllen.

Der Einfachheit halber und zur Veranschaulichung der Formate, die Snowflake voraussichtlich senden und empfangen wird, wird in den meisten Beispielen in diesem Abschnitt davon ausgegangen, dass der Remotedienst Daten im gleichen Format liest und schreibt, das Snowflake erwartet, und dass der Proxydienst Daten unverändert in beide Richtungen weiterleitet.

Unter diesem Thema:

Von Snowflake gesendetes Datenformat

Jede HTTP-Anforderung von Snowflake ist ein POST oder ein GET.

  • Eine POST-Anforderung enthält Header und einen Anforderungstext. Der Anforderungstext enthält einen Batch von Zeilen.

  • Ein GET enthält nur Header und wird nur für das Abrufen verwendet, wenn der Remotedienst Ergebnisse asynchron zurückgibt.

Format des Textkörpers

Der Textköper der POST-Anforderung enthält die Daten, die im JSON-Format serialisiert sind.

Das Schema für JSON lautet:

  • Die oberste Ebene ist ein JSON-Objekt (eine Menge von Name/Wert-Paaren, auch „Wörterbuch“ oder „Dictionary“ genannt).

  • Derzeit gibt es genau einen Eintrag im Wörterbuch. Der Schlüssel für dieses Element heißt „data“.

  • Der Wert dieses „data“-Elements ist ein JSON-Array für das Folgendes gilt:

    • Jedes Element ist genau eine Datenzeile.

    • Jede Datenzeile ist ein JSON-Array aus einer oder mehreren Spalten.

    • Die erste Spalte ist immer die Zeilennummer (d. h. der 0-basierte Index der Zeile innerhalb des Batches).

    • Die verbleibenden Spalten enthalten die Argumente für die Funktion.

  • Datentypen werden wie folgt serialisiert:

    • Nummern werden als JSON-Nummern serialisiert.

    • Boolesche Werte werden als Boolesche JSON-Werte serialisiert.

    • Zeichenfolgen werden als JSON-Zeichenfolgen serialisiert.

    • Objekte werden als JSON-Objekte serialisiert.

    • Alle anderen unterstützten Datentypen werden als JSON-Zeichenfolgen serialisiert.

    • NULL wird als JSON-Null serialisiert.

Beispiele für das Extrahieren von Daten in einem Remotedienst auf jeder Plattform finden Sie unter:

Optional können JSON-Daten für die Übertragung über das Netzwerk komprimiert werden. Die Komprimierung ist in CREATE EXTERNAL FUNCTION dokumentiert.

Beispiel für Textkörper

Hier ist ein Beispiel für eine serialisierte Anforderung für eine externe Funktion mit der Signatur f(integer, varchar, timestamp). Beachten Sie, dass die erste Spalte die Zeilennummer innerhalb des Batches ist und die nächsten drei Werte die Argumente für die externe Funktion sind.

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

Die Header-Informationen stehen dem Remotedienst in der Regel als ein Satz von Schlüssel/Wert-Paaren zur Verfügung. Zu diesen Header-Informationen gehören:

  • Es gibt folgende HTTP-Header:

    • Header, die beschreiben, wie Daten im Body der Anforderung serialisiert sind:

      • „sf-external-function-format“: Dies ist derzeit immer auf „json“ eingestellt.

      • „sf-external-function-format-version“: Dies ist derzeit immer auf „1.0“ eingestellt.

    • „sf-external-function-current-query-id“: Enthält die Abfrage-ID der Abfrage, die diese externe Funktion aufgerufen hat. Sie können diesen Header verwenden, um Snowflake-Abfragen mit Aufrufen des Remotedienstes zu korrelieren, um beispielsweise Probleme zu beheben.

    • „sf-external-function-query-batch-id“: Die Batch-ID ermöglicht die eindeutige Identifizierung des spezifischen Batches von Zeilen, die mit dieser Anforderung verarbeitet werden. Der Remotedienst kann diese ID verwenden, um den Status eines in Bearbeitung befindlichen Batches zu verfolgen. Die ID kann auch als Idempotenztoken verwendet werden, wenn Anforderungen aufgrund eines Fehlers erneut gesendet werden. Die ID kann auch für die Protokollierung/Ablaufverfolgung von Anforderungen durch den Remotedienst verwendet werden.

      Die Batch-ID in einem GET ist die gleiche wie die Batch-ID in dem zugehörigen POST.

      Die Batch-ID ist ein nicht transparenter Wert, der von Snowflake generiert wird. Das Format kann sich in zukünftigen Versionen ändern, sodass sich die Remotedienste nicht auf ein bestimmtes Format verlassen oder versuchen sollten, den Wert zu interpretieren.

    • Header, die die Signatur (Name und Argumenttypen) und den Rückgabetyp der externen Funktion beschreiben, die in der SQL-Abfrage aufgerufen wurde. Diese Werte können Zeichen enthalten, die keine Standardzeichen für Snowflake-Bezeichner sind. Daher sind Base64-Versionen der Informationen enthalten, und Nicht-Standardzeichen werden in den Nicht-Base64-Versionen durch ein Leerzeichen ersetzt.

      Die spezifischen Header sind:

      • 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

      Die für die Funktion ext_func(n integer)  returns varchar gesendeten Header sind zum Beispiel:

      • sf-external-function-name: ext_func

      • sf-external-function-name-base64: <Base64-Wert>

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

      • sf-external-function-signature-base64: <Base64-Wert>

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

      • sf-external-function-return-type-base64: <Base64-Wert>

      Beachten Sie, dass das vom Typ INTEGER deklarierte SQL-Argument als Typ NUMBER beschrieben wird, da SQL INTEGER-Werte wie SQL NUMBER-Wert behandelt werden.

  • Zusätzliche optionale Metadaten, die in den Eigenschaften „headers“ und „context_headers“ von CREATE EXTERNAL FUNCTION beschrieben sind.

Beispiel für Kopfzeilenzugriff

Um den Header „sf-external-function-signature“ aus dem Inneren einer AWS Lambda-Funktion zu extrahieren, die in Python geschrieben ist und die die Header als Python-Wörterbuch empfängt, führen Sie Folgendes aus:

def handler(event, context):

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

Die Details werden sich für andere Sprachen und andere Cloudplattformen unterscheiden.

(Für Remotedienste, die auf AWS entwickelt wurden, finden Sie weitere Informationen zu Header und Lambda-Proxyintegration in der AWS API Gateway-Dokumentation.)

Von Snowflake empfangenes Datenformat

Format des Textkörpers

Wenn ein Remotedienst die Verarbeitung eines Batches abgeschlossen hat, sollte der Remotedienst Daten in einem JSON-Format an Snowflake zurücksenden, das dem Format der von Snowflake gesendeten Daten ähnelt.

Die an Snowflake zurückgegebene JSON-Antwort sollte eine Zeile für jede von Snowflake gesendete Zeile enthalten. Jede zurückgegebene Zeile enthält zwei Werte:

  • Die Zeilennummer (d. h. der 0-basierte Index der Zeile innerhalb des Batches).

  • Der von der Funktion für diese Zeile zurückgegebene Wert. Der Wert kann ein zusammengesetzter Wert sein (z. B. ein OBJECT), muss jedoch genau ein Wert sein, da alle skalaren Snowflake-Funktionen (extern oder anderweitig) einen einzelnen Wert zurückgeben.

Damit Snowflake die Antwort mit der Anforderung korrelieren kann, müssen die Zeilennummern in den zurückgegebenen Daten den Zeilennummern in den von Snowflake gesendeten Daten entsprechen und in derselben Reihenfolge zurückgegeben werden, in der sie empfangen wurden.

Beispiel für Zugriff auf Textkörper

Das folgende JSON-Beispiel zeigt zwei Zeilen mit einem OBJECT-Wert, denen jeweils eine Zeilennummer vorangestellt ist:

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

Um eine dieser zurückgegebenen Zeilen mit Python zusammenzustellen, können Sie den folgenden Code verwenden:

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

Um auf den OBJECT-Wert einer zurückgegebenen Zeile mit SQL zuzugreifen, verwenden Sie die unter Durchsuchen semistrukturierter Daten beschriebene Notation. Beispiel:

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 der Kopfzeile

Die Antwort kann auch die folgenden optionalen HTTP-Header enthalten:

  • Content-MD5: Snowflake verwendet den optionalen Content-MD5-Header, um die Integrität der Antwort zu prüfen. Wenn dieser Header in der Antwort enthalten ist, berechnet Snowflake eine MD5-Prüfsumme für den Textkörper der Antwort, um sicherzustellen, dass er mit der entsprechenden Prüfsumme im zurückgegebenen Header übereinstimmt. Wenn die Werte nicht übereinstimmen, schlägt die SQL-Abfrage fehl. Die Prüfsumme sollte in einer Base64-Darstellung kodiert werden, bevor sie im Header zurückgegeben wird. Betrachten Sie dazu den Beispielcode unten.

Optional können JSON-Daten für die Übertragung über das Netzwerk komprimiert werden. Die Komprimierung ist in CREATE EXTERNAL FUNCTION dokumentiert.

Weitere Informationen zu Timeouts und Wiederholungsversuchen finden Sie unter Konto für Timeout-Fehler und Berücksichtigen, dass Remotedienst mehr als eine Zeile übergeben kann.

Statuscode

Die Antwort enthält außerdem einen HTTP-Statuscode. Snowflake erkennt die folgenden HTTP-Statuscodes:

Code

Beschreibung

200

Batch erfolgreich verarbeitet.

202

Batch erhalten und noch in Bearbeitung.

Andere Werte werden als Fehler behandelt.

Beispiel für das Erstellen einer Antwort

Der folgende Python-Beispielcode gibt eine korrekte Antwort zurück, einschließlich HTTP-Antwortcode, verarbeitete Daten und MD5-Header (der optional ist). (Dies wurde mit Python 3.8 geschrieben.)

Dieses Beispiel basiert auf einer AWS Lambda-Funktion. Einige Codes müssen möglicherweise für andere Plattformen angepasst werden.

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