Erstellen von Java-UDFs¶
Unter diesem Thema wird das Erstellen und Installieren einer benutzerdefinierten Funktion (UDF) erklärt.
Wenn Sie eine Java-UDF erstellen, schreiben Sie Java-Code, den Snowflake als UDF-Logik ausführen soll. Dieser Java-Code ist der Handler der UDF. Sie stellen die UDF mit CREATE FUNCTION bereit, geben der UDF einen Namen und geben die Java-Methode als Handler an, die beim Aufruf der UDF verwendet werden soll.
Weitere Codebeispiele finden Sie unter Beispiele für Java-UDF-Handler.
Unter diesem Thema:
Schreiben des UDF-Handlers in Java¶
Beachten Sie beim Schreiben eines Java-UDF-Handlers die folgenden Anforderungen und Richtlinien.
Definieren Sie die Klasse als „public“.
Deklarieren Sie innerhalb der Klasse mindestens eine öffentliche Methode, die als UDF-Handler verwendet werden soll.
Bei einer Inline-UDF deklarieren Sie nur eine einzige Handler-Methode. Wenn Sie aber beabsichtigen, die Klasse in eine JAR-Datei als vorkompilierte UDF zu packen, können Sie mehrere Handler-Methoden deklarieren und später jede mit der HANDLER-Klausel einer CREATE FUNCTION-Anweisung als Handler spezifizieren.
Sie können bei Bedarf weitere Methoden deklarieren, die von der Handler-Methode aufgerufen werden.
Beachten Sie die folgenden Anforderungen und Richtlinien bei jeder Handler-Methode:
Deklarieren Sie die Handler-Methode als „public“ (öffentlich), entweder statisch oder nicht-statisch.
Wenn die Methode nicht statisch ist, muss Ihre Klasse auch einen Konstruktor mit null Argumenten oder überhaupt keinen Konstruktor deklarieren.
Snowflake übergibt beim Instanziieren der Klasse keine Argumente an den Konstruktor. Wenn der Konstruktor einen Fehler auslöst, wird dieser Fehler zusammen mit der Ausnahmemeldung als Benutzerfehler ausgelöst.
Geben Sie einen geeigneten Rückgabetyp an.
Der Rückgabetyp muss einer der in der Spalte
Java Data Type
der SQL-Java-Typzuordnungstabelle angegebenen Datentypen sein. Der Rückgabetyp muss mit dem SQL-Datentyp kompatibel sein, der in der RETURNS-Klausel der CREATE FUNCTION-Anweisung angegeben ist.Stellen Sie sicher, dass jedes Argument der Handler-Methode (falls vorhanden) ein Datentyp ist, der in der Spalte
Java Data Type
der SQL-Java-Typzuordnungstabelle angegeben ist.Berücksichtigen Sie bei der Auswahl der Datentypen von Java-Variablen die maximal und minimal möglichen Werte der Daten, die von Snowflake gesendet (und an Snowflake zurückgegeben) werden könnten.
Achten Sie in jeder Handler-Methode und den von ihr aufgerufenen Methoden auf die Einhaltung der Snowflake-Einschränkungen für Java-UDFs.
Erstellen der Funktion in Snowflake¶
Die Informationen in diesem Abschnitt gelten für alle Java-UDFs, unabhängig davon, ob der Code inline oder vorkompiliert angegeben wird.
Sie müssen eine CREATE FUNCTION-Anweisung ausführen, bestimmte Aspekte der UDF anzugeben einschließlich:
Name der UDF.
Der Name der Java-Methode, die Snowflake als Handler aufrufen soll, wenn die UDF aufgerufen wird.
Der UDF-Name muss nicht mit dem Namen der in Java geschriebenen Handler-Methode übereinstimmen. Die CREATE FUNCTION-Anweisung verknüpft den UDF-Namen mit der Java-Methode, wie in folgender Abbildung gezeigt:

Bei der Wahl des UDF-Namens beachten Sie Folgendes:
Der Name muss den Regeln für Objektbezeichner folgen.
Wählen Sie einen Namen, der eindeutig ist, oder folgen Sie den Regeln für Überladen von UDF-Namen.
Wichtig
Im Gegensatz zur Überladung bei SQL-UDFs, die zwischen Funktionen sowohl nach der Anzahl als auch nach den Datentypen der Argumente unterscheiden, unterscheiden Java-UDFs Methoden nur nach der Anzahl der Argumente. Wenn zwei Java-Methoden den gleichen Namen und die gleiche Anzahl von Argumenten, aber unterschiedliche Datentypen haben, dann erzeugt der Aufruf einer UDF mit einer dieser Methoden als Handler einen Fehler, der in etwa wie folgt lautet:
Kann nicht bestimmen, welche Implementierung von Handler „Handlername“ aufgerufen werden soll, da es mehrere Definitionen mit <Anzahl der Argumente> Argumenten in Funktion <Name der UDF> mit Handler <Klassenname>.<Handlername> gibt.
Wenn ein Warehouse vorhanden ist, wird der Fehler zum Zeitpunkt der Erstellung der UDF erkannt. Andernfalls tritt der Fehler beim Aufruf der UDF auf.
Das Auflösen auf Basis von Datentypen ist unpraktisch, da einige SQL-Datentypen mehr als einem Java-Datentyp und damit potenziell mehr als einer Java-UDF-Signatur zugeordnet werden können.
Argumente der Handler-Methode werden an die Argumente der UDF über die Position gebunden, nicht über den Namen. Mit anderen Worten: Das erste UDF-Argument wird an das erste Methodenargument übergeben, das zweite UDF-Argument wird an das zweite Methodenargument übergeben, usw.
In den folgenden Beispielen entspricht das SQL-UDF-Argument x
dem Java-Methodenargument a
, und y
entspricht b
:
create function add_int_float(x numeric(9, 0), y float)
returns float
language java
handler = 'MyClass.addIntFloat';
public static float addIntFloat(int a, float b) {
// ...
}
Weitere Informationen zu den Datentypen von Argumenten finden Sie unter Zuordnung von SQL-Java-Datentypen für Parameter und Rückgabetypen.
Bemerkung
Skalare Funktionen (UDFs) haben einen Grenzwert von 500 Eingabeargumenten.
Es wird empfohlen, mit dem Parameter RUNTIME_VERSION der CREATE FUNCTION-Anweisung die zu verwendende unterstützte Java-Laufzeitversion anzugeben, da sich die Standardversion in Zukunft ändern kann.
Inline-UDFs vs. vorkompilierte UDFs¶
Sie können einen Java-UDF-Handler auf eine der folgenden Arten definieren:
Vorkompiliert – Sie packen den kompilierten Java-Handler in eine JAR-Datei und speichern diese dort, wo Snowflake sie lesen kann.
Die CREATE FUNCTION-Anweisung gibt den Speicherort der JAR-Datei an, die den Handler enthält. Vor dem Ausführen von CREATE FUNCTION müssen Sie die JAR-Datei in den Stagingbereich kopieren, aus dem Snowflake die Datei lesen kann.
Inline – Sie binden den Java-Code mit der UDF-Deklaration selbst ein.
Die CREATE FUNCTION-Anweisung gibt dann den Java-Quellcode selbst an. Snowflake kompiliert den Quellcode und speichert den kompilierten Code in einer JAR-Datei. Beim Ausführen von CREATE FUNCTION können Sie mit der TARGET_PATH-Klausel einen Speicherort für die resultierende JAR-Datei angeben.
Wenn CREATE FUNCTION einen Speicherort für die JAR-Datei angibt, kompiliert Snowflake den Code einmal und behält die JAR-Datei für die zukünftige Verwendung.
Wenn CREATE FUNCTION keinen Speicherort für die JAR-Datei angibt, führt Snowflake eine erneute Kompilierung des Codes für jede SQL-Anweisung durch, die die UDF-Anweisung aufruft, und Snowflake bereinigt die JAR-Datei automatisch, nachdem die SQL-Anweisung beendet ist.
Praktische Unterschiede¶
Vorteile von Inline-Java-UDFs¶
Sie sind in der Regel einfacher zu implementieren. Nachdem Sie mit Ihren Entwicklungstools überprüft haben, ob Ihr Code ordnungsgemäß funktioniert, können Sie ihn bereitstellen, indem Sie den Code in die CREATE FUNCTION-Anweisung kopieren und dann die Anweisung ausführen. Sie können den Code dort pflegen, CREATE FUNCTION aktualisieren und ausführen, ohne die kompilierte Ausgabe separat in eine JAR-Datei umpacken und in einem Stagingbereich aktualisieren zu müssen.
Vorteile von vorkompilierten Java-UDFs¶
Sie können sie verwenden, wenn Sie eine JAR-Datei, aber keinen Quellcode haben.
Sie können sie verwenden, wenn der Quellcode zu groß ist, um ihn in eine CREATE FUNCTION-Anweisung einzufügen. (Inline-Java-UDFs haben eine Obergrenze für die Quellcodegröße.)
Eine vorkompilierte Java-UDF kann mehrere Handler-Funktionen enthalten. Mehrere CREATE FUNCTION-Anweisungen können auf dieselbe JAR-Datei verweisen, geben aber unterschiedliche Handlerfunktionen innerhalb der JAR-Datei an.
Inline-Java-UDFs enthalten normalerweise nur eine aufrufbare Funktion. (Diese aufrufbare Funktion kann andere Funktionen aufrufen, und diese anderen Funktionen können in derselben Klasse oder in anderen in den JAR-Bibliotheksdateien definierten Klassen definiert sein).
Wenn Sie über Tools oder eine Umgebung zum Testen oder Debuggen von JAR-Dateien verfügen, kann es bequemer sein, den größten Teil der Entwicklungsarbeit an Ihrer UDF mit JAR-Dateien zu erledigen. Dies gilt insbesondere, wenn der Code groß oder komplex ist.
Hinzufügen von Abhängigkeiten zum Klassenpfad¶
Wenn Ihr Handler-Code Klassen benötigt, die in externen JAR-Dateien verpackt sind, können Sie diese Abhängigkeiten dem von Snowflake verwalteten Klassenpfad hinzufügen, der für Ihren Handler verfügbar ist. Im Folgenden wird beschrieben, wie JAR-Dateien dem Klassenpfad hinzufügt werden, der für einen Java-UDF Handler sichtbar ist.
Erstellen Sie einen Stagingbereich, auf den Ihr Handler zugreifen kann.
Für UDF-Abhängigkeiten können Sie einen externen Stagingbereich oder eine interne Stagingbereich verwenden. Wenn Sie einen internen Stagingbereich verwenden, muss es sich um einen Benutzer- oder benannten Stagingbereich handeln. Snowflake unterstützt derzeit nicht die Verwendung von Tabellen-Stagingbereichen für UDF-Abhängigkeiten. Weitere Informationen zum Erstellen eines Stagingbereichs finden Sie unter CREATE STAGE. Weitere Informationen zur Auswahl des Typs eines internen Stagingbereichs finden Sie unter Auswahl eines internen Stagingbereichs für lokale Dateien.
Kopieren Sie die JAR-Datei mit den Abhängigkeiten in den Stagingbereich.
Sie können die JAR-Datei von einem lokalen Laufwerk in einen Stagingbereich kopieren, indem Sie den Befehl PUT verwenden. Weitere Informationen zu diesem Befehl finden Sie unter PUT. Weitere Informationen zum Staging von Dateien mit PUT finden Sie unter Staging von Datendateien aus einem lokalen Dateisystem.
Verweisen Sie beim Erstellen der UDF auf die JAR-Datei mit den Abhängigkeit.
Wenn Sie CREATE FUNCTION ausführen, um die UDF zu erstellen, geben Sie Speicherort und Dateipfad/Dateiname im Stagingbereich für alle abhängigen JAR-Dateien als Werte der IMPORTS-Klausel an. Zur Laufzeit fügt Snowflake die JAR-Datei zum Klassenpfad hinzu. Weitere Informationen dazu finden Sie unter CREATE FUNCTION.
Im folgenden Beispielcode wird eine UDF mit dem Namen
my_udf
erstellt, die einemy_handler_dependency.jar
-Abhängigkeit vom Stagingbereich@mystage
angibt.CREATE FUNCTION my_udf(i NUMERIC) RETURNS NUMERIC LANGUAGE JAVA IMPORTS = ('@mystage/dependencies/my_handler_dependency.jar') HANDLER = 'MyClass.myFunction' AS $$ // Handler code omitted. $$
Erstellen einer Inline-Java-UDF¶
Bei einer Inline-UDF stellen Sie den Java-Quellcode als Teil der CREATE FUNCTION-Anweisung bereit.
Sie fügen den Java-Quellcode in die AS-Klausel ein und umschließen den Code mit einfachen Anführungszeichen oder einem Paar von Dollarzeichen ($$
). Möglicherweise ist die Verwendung von doppelten Dollarzeichen einfacher, z. B. wenn der Quellcode eingebettete einfache Anführungszeichen enthält.
Der Code im folgenden Beispiel deklariert eine add
-UDF, deren Handler die Methode add
in der Klasse TestAddFunc
ist.
create function add(x integer, y integer)
returns integer
language java
handler='TestAddFunc.add'
target_path='@~/TestAddFunc.jar'
as
$$
class TestAddFunc {
public static int add(int x, int y) {
return x + y;
}
}
$$;
Angenommen, der Java-Quellcode kann mehr als eine Klasse und mehr als eine Methode in einer Klasse enthalten. Dann werden Klasse und Methode für den Aufruf in der HANDLER-Klausel angegeben.
Eine Inline-Java-UDF (wie auch eine vorkompilierte Java-UDF) kann Code in JAR-Dateien aufrufen, die in der IMPORTS-Klausel der CREATE FUNCTION-Anweisung enthalten sind.
Weitere Informationen zur CREATE FUNCTION-Anweisung finden Sie unter CREATE FUNCTION.
Weitere Beispiele finden Sie unter Beispiele für Java-UDF-Handler.
Erstellen einer vorkompilierten Java-UDF¶
Wenn Sie beabsichtigen, einen UDF zu erstellen, die den Speicherort einer vorhandenen JAR-Datei für den Handler angibt, entwickeln Sie den Handler wie folgt:
Organisieren der Codedateien in einer Hierarchie für das Packen in eine JAR-Datei.
Kopieren der JAR-Datei mit der Handler-Funktion in einen Stagingbereich, in dem Snowflake die Datei zur Laufzeit lesen kann.
Organisieren Ihrer Dateien¶
Wenn Sie vorhaben, den Java-Code zu kompilieren, um die JAR-Datei selbst zu erstellen, können Sie die Dateien wie unten gezeigt organisieren. Dieses Beispiel geht davon aus, dass Sie den Package-Mechanismus von Java verwenden möchten.
Entwicklungsverzeichnis
Paketverzeichnis
Klassendatei1.java
Klassendatei2.java
classDirectory
Klassendatei1.class
Klassendatei2.class
Manifestdatei.manifest (optional)
jar_Datei.jar
put_Befehl.sql
developmentDirectory
Dieses Verzeichnis enthält die projektspezifischen Dateien, die zum Erstellen Ihrer Java-UDF erforderlich sind.
packageDirectory
Dieses Verzeichnis enthält die .java-Dateien, die kompiliert und in das Paket aufgenommen werden sollen.
class_file#.java
Diese Dateien enthalten den Java-Quellcode der UDF.
class_file#.class
Dies sind die .class-Dateien, die durch Kompilieren der .java-Dateien erstellt werden.
manifest_file.manifest
Die optionale Manifestdatei, die beim Kombinieren der .class-Dateien (und optional der Abhängigkeits-JAR-Dateien) in der JAR-Datei verwendet werden.
jar_file.jar
Die JAR-Datei, die den UDF-Code enthält.
put_command.sql
Diese Datei enthält den SQL-Befehl PUT zum Kopieren der JAR-Datei in einen Snowflake-Stagingbereich.
Kompilieren des Java-Codes und Erstellen der JAR-Datei¶
So erstellen Sie eine JAR-Datei, die den kompilierten Java-Code enthält:
Verwenden Sie javac, um Ihre .java-Datei in eine .class-Datei zu kompilieren.
Wenn Sie einen Compiler neuer als Version 11.x verwenden, können Sie mit der Option „–release“ angeben, dass die Zielversion Version 11 ist.
Legen Sie Ihre .class-Datei in eine JAR-Datei. Sie können mehrere Klassendateien (und andere JAR-Dateien) in Ihre JAR-Datei packen.
Beispiel:
jar cf ./my_udf.jar MyClass.class
Eine Manifestdatei ist erforderlich, wenn sich Ihre Handler-Klasse in einem Paket befindet, andernfalls ist sie optional. Im folgenden Beispiel wird eine Manifestdatei verwendet:
jar cmf my_udf.manifest ./my_udf.jar example/MyClass.class
Um die JAR-Datei mit allen enthaltenen Abhängigkeiten zu erstellen, können Sie den Maven-Befehl
mvn package
mit dem maven-assembly-plugin verwenden. Weitere Informationen zum maven-assembly-plugin finden Sie auf der Seite zur Maven-Nutzung.Snowflake stellt automatisch die Standard-Java-Bibliotheken (z. B.
java.util
) bereit. Wenn Ihr Code diese Bibliotheken aufruft, müssen Sie sie nicht in Ihre JAR-Datei aufnehmen.Die Methoden, die Sie in Bibliotheken aufrufen, müssen denselben Snowflake-bedingten Einschränkungen folgen wie Ihre Java-Methode.
Kopieren der JAR-Datei in Ihren Stagingbereich¶
Damit Snowflake aus der JAR-Datei, die Ihre Handler-Methode enthält, lesen kann, müssen Sie die JAR-Datei in eine der folgenden Arten von Stagingbereich kopieren:
Ein Benutzer oder ein benannter interner Stagingbereich.
Snowflake unterstützt derzeit nicht die Verwendung eines Tabellen-Stagingbereichs zur Speicherung einer JAR-Datei, die UDF-Handler enthält. Weitere Informationen zu internen Stagingbereichen finden Sie unter Auswahl eines internen Stagingbereichs für lokale Dateien.
Ein externer Stagingbereich.
Der Stagingbereich, der die JAR-Datei hostet, muss für den Eigentümer der UDF-Datei lesbar sein.
Normalerweise laden Sie die JAR-Datei mit dem Befehl PUT in einen benannten internen Stagingbereich hoch. Beachten Sie, dass Sie den Befehl PUT
nicht über die Snowflake-GUI ausführen können. Sie können aber SnowSQL verwenden, um PUT
auszuführen. Im Abschnitt Beispiele für Java-UDF-Handler finden Sie ein Beispiel für die Verwendung des PUT
-Befehls zum Kopieren einer .jar-Datei in einen Stagingbereich.
Weitere Informationen zum Erstellen von Stagingbereichen finden Sie unter CREATE STAGE.
Beschränkungen und Best Practices
Wenn Sie die JAR-Datei löschen oder umbenennen, können Sie die UDF-Datei nicht mehr aufrufen.
Wenn Sie Ihre JAR-Datei aktualisieren müssen, gehen Sie wie folgt vor:
Aktualisieren Sie die Datei, wenn keine Aufrufe an die UDF erfolgen können.
Wenn sich die alte .jar-Datei noch im Stagingbereich befindet, muss der
PUT
-Befehl dieOVERWRITE=TRUE
-Klausel enthalten.
Bemerkung
Ein Benutzer, der Aktionen im Zusammenhang mit UDFs ausführt, muss über eine Rolle verfügen, der die für die Aktion erforderlichen Berechtigungen zugewiesen wurden. Weitere Informationen dazu finden Sie unter Erteilen von Berechtigungen für benutzerdefinierte Funktionen.