Création d’UDFs Java

Cette rubrique montre comment créer et installer une fonction Java définie par l’utilisateur (UDF).

Lorsque vous écrivez une UDF Java, vous écrivez du code Java pour que Snowflake l’exécute comme une logique UDF. Ce code Java est le gestionnaire de l’UDF. Vous déployez l’UDF avec le CREATE FUNCTION, en donnant un nom à l’UDF et en spécifiant la méthode Java comme gestionnaire à utiliser lors de l’appel de l’UDF.

Pour plus d’exemples de code, voir Exemples de gestionnaires d’UDF Java.

Dans ce chapitre :

Écriture du gestionnaire de l’UDF en Java

Utilisez les exigences et les lignes directrices suivantes lors de l’écriture de votre gestionnaire d’UDF Java.

  • Définissez la classe comme publique.

  • Dans la classe, déclarez au moins une méthode publique à utiliser comme gestionnaire d’UDF.

    Pour une UDF en ligne, déclarez une seule méthode de gestionnaire. Si, au contraire, vous avez l’intention d’empaqueter la classe dans un JAR en tant qu’UDF précompilée , vous pouvez déclarer plusieurs méthodes de gestionnaire, puis ensuite spécifier chacune d’elles en tant que gestionnaire avec la clause HANDLER d’une instruction CREATE FUNCTION.

    Vous pouvez déclarer d’autres méthodes, si nécessaire, qui seront appelées par la méthode de gestionnaire.

    Utilisez les exigences et les lignes directrices suivantes pour chaque méthode de gestionnaire :

    • Déclarez la méthode de gestionnaire comme publique, soit statique, soit non statique.

      Si la méthode n’est pas statique, votre classe doit également déclarer un constructeur à zéro argument ou pas de constructeur du tout.

      Snowflake ne transmet aucun argument au constructeur lorsqu’il instancie la classe. Si le constructeur génère une erreur, celle-ci est signalée comme une erreur de l’utilisateur, avec le message d’exception.

    • Spécifiez un type de retour approprié.

      Le type de retour doit être l’un des types de données spécifiés dans la colonne Java Data Type de la table SQL-Java Type Mappings. Le type de retour doit être compatible avec le type de données SQL spécifié dans la clause RETURNS de l’instruction CREATE FUNCTION.

    • Assurez-vous que chaque argument de méthode de gestionnaire (le cas échéant) est un type de données spécifié dans la colonne Java Data Type de la table SQL-Java Type Mappings.

      Lorsque vous choisissez les types de données des variables Java, tenez compte des valeurs maximales et minimales possibles des données qui pourraient être envoyées de (et retournées à) Snowflake.

    • Respectez les contraintes imposées par Snowflake pour les UDFs Java dans chaque méthode du gestionnaire et dans les méthodes qu’il appelle.

Création de la fonction dans Snowflake

Les informations de cette section s’appliquent à toutes les UDFs Java, que le code soit spécifié en ligne ou précompilé.

Vous devez exécuter une instruction CREATE FUNCTION pour spécifier les aspects de l’UDF, notamment :

  • Le nom de l’UDF.

  • Le nom de la méthode Java que Snowflake doit appeler en tant que gestionnaire lors de l’appel de l’UDF.

Le nom de l’UDF ne doit pas nécessairement correspondre au nom de la méthode du gestionnaire écrite en Java. L’instruction CREATE FUNCTION associe le nom de l’UDF à la méthode Java, comme montré dans le diagramme suivant :

Using the CREATE FUNCTION Statement to Associate the Handler Method With the UDF Name

Pour choisir un nom pour l’UDF :

  • Suivez les règles de Identificateurs d’objet.

  • Choisissez un nom qui soit unique, ou suivez les règles pour Surcharge de noms d’UDF.

    Important

    Contrairement à la surcharge pour les UDFs SQL, qui distingue les fonctions en fonction du nombre et des types de données des arguments, les UDFs Java distinguent les méthodes en fonction uniquement du nombre d’arguments. Si deux méthodes Java ont le même nom et le même nombre d’arguments, mais des types de données différents, l’appel d’une UDF utilisant l’une de ces méthodes comme gestionnaire génère une erreur similaire à la suivante :

    Impossible de déterminer l’implémentation du gestionnaire « nom du gestionnaire » à appeler, car il existe plusieurs définitions avec <nombre d’arguments> arguments dans la fonction <nom de la fonction définie par l’utilisateur> avec le gestionnaire <nom de la classe>.<nom du handler>

    Si un entrepôt est disponible, l’erreur est détectée au moment où l’UDF est créée. Sinon, l’erreur se produit lors de l’appel de l’UDF.

    La résolution basée sur les types de données n’est pas pratique car certains types de données SQL peuvent être mappés à plus d’un type de données Java et donc potentiellement à plus d’une signature UDF Java.

Les arguments de la méthode du gestionnaire sont liés aux arguments de l’UDF par leur position, et non par leur nom. En d’autres termes, le premier argument de l’UDF est transmis au premier argument de la méthode, le deuxième argument de l’UDF est transmis au deuxième argument de la méthode, et ainsi de suite.

Dans les exemples ci-dessous, l’argument de l’UDF SQL x correspond à l’argument a de la méthode Java et y correspond à 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) {
  // ...
}

Pour plus d’informations sur les types de données des arguments, voir Mappages de type de donnée SQL-Java pour les paramètres et les types de retour.

Note

Les fonctions scalaires (UDFs) ont une limite de 500 arguments d’entrée.

Il est recommandé d’utiliser le paramètre RUNTIME_VERSION de l’instruction CREATE FUNCTION pour spécifier la version du moteur d’exécution Java à utiliser, car la version par défaut peut changer à l’avenir.

UDFs en ligne vs. UDFs pré-compilées

Vous pouvez définir un gestionnaire d’UDF Java de l’une des manières suivantes :

  • Pré-compilé, dans lequel vous empaquetez le gestionnaire Java compilé dans un JAR et le placez là où Snowflake peut le lire.

    L’instruction CREATE FUNCTION spécifie l’emplacement du fichier JAR contenant le gestionnaire. Avant d’exécuter CREATE FUNCTION, vous copiez le fichier JAR vers une zone de préparation à partir de laquelle Snowflake peut le lire.

  • En ligne, dans lequel vous incluez le code Java avec la déclaration de l’UDF elle-même.

    L’instruction CREATE FUNCTION elle-même spécifie le code source Java. Snowflake compile le code source et stocke le code compilé dans un fichier JAR. Vous pouvez spécifier un emplacement pour le fichier JAR résultant avec la clause TARGET_PATH lorsque vous exécutez CREATE FUNCTION.

    • Si CREATE FUNCTION spécifie un emplacement pour le fichier JAR, alors Snowflake compile le code une fois et conserve le fichier JAR pour une utilisation ultérieure.

    • Si CREATE FUNCTION ne spécifie pas d’emplacement pour le fichier JAR, alors Snowflake recompile le code pour chaque instruction SQL qui appelle l’UDF, et Snowflake nettoie automatiquement le fichier JAR après la fin de l’instruction SQL.

Différences pratiques

Avantages de l’UDF Java en ligne

  • Elles sont généralement plus faciles à mettre en œuvre. Après avoir utilisé vos outils de développement pour vérifier que votre code fonctionne comme il le devrait, vous pouvez le déployer en le copiant dans l’instruction CREATEFUNCTION puis en exécutant l’instruction. Vous pouvez y maintenir le code, en mettant à jour et en exécutant CREATE FUNCTION, sans avoir à réempaqueter séparément la sortie compilée dans un JAR et à la mettre à jour dans une zone de préparation.

Avantages des UDF Java précompilées

  • Vous pouvez les utiliser lorsque vous avez un fichier JAR mais pas de code source.

  • Vous pouvez les utiliser si le code source est trop volumineux pour être collé dans une instruction CREATE FUNCTION. (Les UDFs Java en ligne ont une limite supérieure sur la taille du code source).

  • Une UDF Java précompilée peut contenir plusieurs fonctions de gestionnaire. Plusieurs instructions CREATE FUNCTION peuvent faire référence au même fichier JAR mais spécifient différentes fonctions de handler dans le fichier JAR.

    Les UDFs Java en ligne ne contiennent normalement qu’une seule fonction appelable. (Cette fonction appelable peut appeler d’autres fonctions, et ces autres fonctions peuvent être définies dans la même classe ou peuvent être définies dans d’autres classes définies dans les fichiers de la bibliothèque JAR).

  • Si vous disposez d’outils ou d’un environnement pour tester ou déboguer les fichiers JAR, il peut être plus pratique d’effectuer la majeure partie du travail de développement sur vos UDF en utilisant des fichiers JAR. Cela est particulièrement vrai si le code est vaste ou complexe.

Ajouter des dépendances au Classpath

Lorsque le code de votre gestionnaire nécessite des classes empaquetées dans des fichiers JAR externes, vous pouvez ajouter ces dépendances au classpath géré par Snowflake disponible pour votre gestionnaire. Ce qui suit décrit comment ajouter des fichiers JAR au classpath visible par un gestionnaire d’UDF Java.

  1. Créez une zone de préparation qui est disponible pour votre gestionnaire.

    Pour les dépendances d’UDF, vous pouvez utiliser une zone de préparation externe ou une zone de préparation interne. Si vous utilisez une zone de préparation interne, il doit s’agir d’une zone de préparation d’utilisateur ou nommée ; Snowflake ne prend actuellement pas en charge l’utilisation d’une zone de préparation de table pour des dépendances d’UDF. Pour en savoir plus sur la création d’une zone de préparation, voir CREATE STAGE. Pour en savoir plus sur le choix d’un type de zone de préparation interne, voir Choix d’une zone de préparation interne pour les fichiers locaux.

  2. Copier le fichier JAR de dépendance dans la zone de préparation.

    Vous pouvez copier le fichier JAR d’un lecteur local vers une zone de préparation en utilisant la commande PUT. Pour la référence de la commande, voir PUT. Pour des informations sur la mise en zone de préparation de fichiers avec PUT, voir Mise en zone de préparation des fichiers de données à partir d’un système de fichiers local.

  3. Référencer la dépendance JAR lorsque vous créez l’UDF.

    Lorsque vous exécutez CREATE FUNCTION pour créer l’UDF, spécifiez l’emplacement de la zone de préparation et le chemin et le nom de fichier de tous les fichiers JAR de dépendance comme valeurs de la clause IMPORTS. Au moment de l’exécution, Snowflake ajoute le fichier JAR au classpath. Pour des informations de référence, voir CREATE FUNCTION.

    Le code de l’exemple suivant crée une UDF appelée my_udf, en spécifiant une dépendance my_handler_dependency.jar sur la zone de préparation @mystage.

    CREATE FUNCTION my_udf(i NUMERIC)
      RETURNS NUMERIC
      LANGUAGE JAVA
      IMPORTS = ('@mystage/dependencies/my_handler_dependency.jar')
      HANDLER = 'MyClass.myFunction'
      AS
      $$
        // Handler code omitted.
      $$
    

Création d’une UDF Java en ligne

Pour une UDF en ligne, vous fournissez le code source Java dans le cadre de l’instruction CREATE FUNCTION.

Vous placez le code source Java dans la clause AS en entourant le code de guillemets simples ou d’une paire de signes dollar ($$). L’utilisation du double signe dollar peut être plus facile, par exemple lorsque le code source contient des guillemets simples intégrés.

Le code de l’exemple suivant déclare une UDF add dont le gestionnaire est la méthode add de la classe TestAddFunc.

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;
        }
    }
$$;

Le code source Java peut contenir plus d’une classe et plus d’une méthode dans une classe. La clause HANDLER spécifie donc la classe et la méthode à utiliser comme gestionnaire.

Une UDF Java en ligne (comme une UDF Java précompilée) peut appeler du code dans des fichiers JAR qui sont inclus dans la clause IMPORTS de l’instruction CREATEFUNCTION.

Pour plus de détails sur la syntaxe de l’instruction CREATE FUNCTION, voir CREATE FUNCTION.

Pour plus d’exemples, voir Exemples de gestionnaires d’UDF Java.

Création d’une UDF Java précompilée

Lorsque vous avez l’intention de créer une UDF qui spécifie l’emplacement d’un fichier JAR existant pour son gestionnaire, vous développez le gestionnaire de cette façon :

Organiser vos fichiers

Si vous prévoyez de compiler vous-même le code Java pour créer le fichier JAR, vous pouvez organiser les fichiers comme indiqué ci-dessous. Cet exemple suppose que vous prévoyez d’utiliser le mécanisme de paquetage de Java.

  • developmentDirectory

    • packageDirectory

      • class_file1.java

      • class_file2.java

    • classDirectory

      • class_file1.class

      • class_file2.class

    • manifest_file.manifest (facultatif)

    • jar_file.jar

    • put_command.sql

developmentDirectory

Ce répertoire contient les fichiers spécifiques au projet nécessaires à la création de votre UDF Java.

packageDirectory

Ce répertoire contient les fichiers .java à compiler et à inclure dans le paquet.

class_file#.java

Ces fichiers contiennent le code source Java de l’UDF.

class_file#.class

Il s’agit du ou des fichiers .class créés en compilant des fichiers .java.

manifest_file.manifest

Le fichier manifeste facultatif utilisé lors de la combinaison des fichiers .class (et éventuellement des fichiers JAR de dépendance) dans le fichier JAR.

jar_file.jar

Le fichier JAR qui contient le code de l’UDF.

put_command.sql

Ce fichier contient la commande SQL PUT permettant de copier le fichier JAR vers une zone de préparation Snowflake.

Compilation du code Java et création du fichier JAR

Pour créer un fichier JAR qui contient le code Java compilé :

  • Utilisez javac pour compiler votre fichier .java en un fichier .class.

    Si vous utilisez un compilateur plus récent que la version 11.x, vous pouvez utiliser l’option « –release » pour spécifier que la version cible est la version 11.

  • Placez votre fichier .class dans un fichier JAR. Vous pouvez regrouper plusieurs fichiers de classe (et d’autres fichiers JAR) dans votre fichier JAR.

    Par exemple :

    jar cf ./my_udf.jar MyClass.class
    

    Un fichier manifeste est obligatoire si votre classe de gestionnaire fait partie d’un paquet, et facultatif dans le cas contraire. L’exemple suivant utilise un fichier manifeste :

    jar cmf my_udf.manifest ./my_udf.jar example/MyClass.class
    

    Pour construire le fichier jar avec toutes les dépendances incluses, vous pouvez utiliser la commande mvn package de Maven avec le maven-assembly-plugin. Pour plus d’informations sur le plugin maven-assembly, voir la page sur l’utilisation de Maven.

    Snowflake fournit automatiquement les bibliothèques Java standards (par exemple, java.util). Si votre code fait appel à ces bibliothèques, vous n’avez pas besoin de les inclure dans votre fichier JAR.

    Les méthodes que vous appelez dans les bibliothèques doivent respecter les mêmes contraintes imposées par Snowflake que votre méthode Java.

Copie du fichier JAR dans votre zone de préparation

Pour que Snowflake puisse lire le fichier JAR contenant votre méthode de gestionnaire, vous devez copier le fichier JAR dans l’un des types de zone de préparation suivants :

  • Une zone de préparation interne utilisateur ou nommée.

    Snowflake ne prend actuellement pas en charge l’utilisation d’une zone de préparation de table pour stocker un fichier JAR avec des gestionnaires UDF. Pour en savoir plus sur les zones de préparation internes, voir Choix d’une zone de préparation interne pour les fichiers locaux.

  • Zone de préparation externe.

La zone de préparation hébergeant le fichier JAR doit être lisible par le propriétaire de l’UDF.

Typiquement, vous chargez le fichier JAR vers une zone de préparation interne nommée en utilisant la commande PUT. Notez que vous ne pouvez pas exécuter la commande PUT par la GUI de Snowflake ; vous pouvez utiliser SnowSQL pour exécuter PUT. Voir la section Exemples de gestionnaires d’UDF Java pour un exemple de commande PUT pour copier un fichier .jar dans une zone de préparation.

Pour plus d’informations sur la création de zones de préparation, voir CREATE STAGE.

Mises en garde et meilleures pratiques

Si vous supprimez ou renommez le fichier JAR, vous ne pouvez plus appeler l’UDF.

Si vous devez mettre à jour votre fichier JAR, alors :

  • Mettez-le à jour tant qu’aucun appel vers l’UDF ne peut être fait.

  • Si l’ancien fichier .jar se trouve toujours dans la zone de préparation, la commande PUT doit inclure la clause OVERWRITE=TRUE.

Note

Un utilisateur effectuant une action liée à des UDFs doit avoir un rôle auquel ont été attribuées les autorisations requises pour cette action. Pour plus d’informations, voir Accorder des privilèges pour les fonctions définies par l’utilisateur.

Revenir au début