UDFs Java tabulaires (UDTFs)

Ce document explique comment écrire une UDTF (fonction de table définie par l’utilisateur) en Java.

Dans ce chapitre :

Introduction

Une UDTF peut être écrite dans l’un des langages suivants :

  • SQL

  • JavaScript

  • Java

Chaque UDTF est créée en exécutant l’instruction CREATE FUNCTION qui spécifie :

  • Les types de données des arguments transmis à l’UDTF.

  • Les types de données des colonnes dans les lignes renvoyées par l’UDTF.

  • Le code à exécuter lorsque l’UDTF est appelée. Par exemple, si l’UDTF est implémenté comme une UDTF JavaScript, alors l’instruction CREATE FUNCTION spécifie la fonction JavaScript à appeler.

Un développeur UDTF crée une fonction (ou méthode) par ligne, qui est appelée une fois pour chaque ligne d’entrée. La méthode par ligne accepte zéro ou plusieurs paramètres. Pour chaque ligne d’entrée, la méthode par ligne renvoie un ensemble de zéro, une ou plusieurs lignes de sortie.

Actuellement, les UDTFs écrites dans toutes les langues prises en charge, à l’exception de SQL, présentent les caractéristiques supplémentaires suivantes :

  • Les rangées peuvent éventuellement être regroupées en partitions. Toutes les lignes d’une partition sont traitées ensemble (c’est-à-dire qu’elles sont transmises séquentiellement à la même instance de la méthode par ligne). La sortie peut éventuellement contenir une ou plusieurs lignes basées sur des caractéristiques communes de lignes au sein de la partition.

    • Pour les données partitionnées, les UDTFs prennent en charge une méthode facultative initialiseur qui est appelée une fois par partition, avant que la méthode par ligne ne commence à traiter la première ligne de la partition. La méthode d’initialiseur peut initialiser des variables à utiliser pour l’ensemble de la partition.

    • Pour les données partitionnées, les UDTFs prennent en charge une méthode facultative finaliseur qui est appelée une fois par partition, après que la méthode par ligne a fini de traiter la dernière ligne de la partition. La méthode finaliseur permet au code de renvoyer zéro, une ou plusieurs lignes de sortie qui ne sont pas liées à une ligne d’entrée spécifique. Les lignes de sortie peuvent être :

      • Des lignes qui sont ajoutées à la sortie déjà générée pour la partition.

      • Une ou plusieurs lignes qui résument la partition. Dans ce cas, la méthode par lignes n’a peut-être pas généré de lignes d’entrée ; elle a peut-être simplement effectué des calculs qui sont utilisés par la méthode finaliseur lorsque celle-ci génère ses lignes de sortie.

    La colonne sur laquelle il faut partitionner les lignes est spécifiée dans l’instruction SQL qui appelle l’instruction UDTF.

    Pour plus d’informations sur le partitionnement, voir Fonctions et partitions des tables.

Pour les UDTFs Java, la méthode initialiseur, la méthode par ligne et la méthode finaliseur sont mises en œuvre comme décrit ci-dessous :

  • L’initialiseur est mis en œuvre en écrivant un constructeur à zéro argument.

  • La méthode par ligne est nommée process().

  • Le finaliseur est mis en œuvre comme une méthode à zéro argument nommée endPartition().

Chaque UDTF Java nécessite une classe de gestion, qui définit le constructeur, process(), et endPartition(). Les détails sont inclus dans Classes Java pour UDTFs (dans cette rubrique).

Chaque UDTF Java nécessite également une classe de ligne de sortie, qui spécifie les types de données Java des colonnes de la ou des lignes de sortie générées par la classe de gestion. Les détails sont inclus dans La classe de ligne de sortie (dans cette rubrique).

Note

Les fonctions tabulaires (UDTFs) ont une limite de 500 arguments d’entrée et 500 colonnes de sortie.

Classes Java pour UDTFs

Les principaux composants de l’UDTF sont la classe de gestion et la classe de ligne de sortie.

La classe de gestion

Snowflake interagit avec l’UDTF principalement en appelant les méthodes suivantes de la classe de gestion :

  • L’initialiseur (le constructeur).

  • La méthode par ligne (process()).

  • La méthode finaliseur (endPartition()).

La classe de gestion peut contenir des méthodes supplémentaires nécessaires à la prise en charge de ces trois méthodes.

La classe de gestionnaire contient également une méthode getOutputClass(), qui est décrite plus loin.

Le lancement d’une exception à partir de n’importe quelle méthode de la classe de gestion (ou de la ligne de sortie) entraîne l’arrêt du traitement. La requête qui a appelé l’UDTF échoue avec un message d’erreur.

Le constructeur

Une classe de gestion peut avoir un constructeur, qui doit prendre zéro argument.

Le constructeur est appelé une fois pour chaque partition avant tout appel de process().

Le constructeur ne peut pas produire de lignes de sortie.

Utilisez le constructeur pour initialiser l’état de la partition ; cet état peut être utilisé par les méthodes process() et endPartition(). Le constructeur est également l’endroit approprié pour placer toute initialisation de longue durée qui doit être effectuée une seule fois par partition plutôt qu’une fois par ligne.

Le constructeur est facultatif.

La méthode process()

Cette méthode process() est appelée une fois pour chaque ligne de la partition d’entrée.

Les arguments transmis à l’UDTF sont transmis à process(). Les valeurs des arguments sont converties de types de données SQL en types de données Java. (Pour des informations sur le mappage de type de données SQL et Java, voir Mappages de type de donnée SQL-Java pour les paramètres et les types de retour).

Les noms des paramètres de la méthode process() peuvent être n’importe quels identificateurs Java valides ; les noms ne doivent pas nécessairement correspondre aux noms spécifiés dans l’instruction CREATE FUNCTION.

Chaque fois que process() est appelée, elle peut renvoyer zéro, une ou plusieurs lignes.

Le type de données renvoyé par la méthode process() doit être Stream<OutputRow>, où le flux (Stream) est défini dans java.util.stream.Stream et OutputRow est le nom de la classe de ligne de sortie. L’exemple ci-dessous montre une méthode process() simple qui renvoie simplement son entrée via un flux :

import java.util.stream.Stream;

...

public Stream<OutputRow> process(String v) {
  return Stream.of(new OutputRow(v));
}

...

Si la méthode process ne conserve ou n’utilise aucun état dans l’objet (par exemple, si la méthode est conçue pour exclure de la sortie les lignes d’entrée sélectionnées), vous pouvez déclarer la méthode static. Si la méthode process est static et que la classe du gestionnaire ne possède pas de constructeur ou de méthode endPartition non statique, Snowflake transmet chaque ligne directement à la méthode process statique sans construire une instance de la classe du gestionnaire.

Si vous devez ignorer une ligne d’entrée et traiter la ligne suivante (par exemple, si vous validez les lignes d’entrée), renvoyez un objet Stream vide. Par exemple, la méthode process ci-dessous ne renvoie que les lignes pour lesquelles number est un nombre entier positif. Si number n’est pas positif, la méthode renvoie un objet Stream vide pour ignorer la ligne actuelle et poursuivre le traitement de la ligne suivante.

public Stream<OutputRow> process(int number) {
  if (inputNumber < 1) {
    return Stream.empty();
  }
  return Stream.of(new OutputRow(number));
}

Si process() renvoie un flux nul, le traitement s’arrête. (La méthode endPartition() est toujours appelée même si un flux nul est renvoyé).

Cette méthode est requise.

La méthode endPartition()

Cette méthode peut être utilisée pour générer des lignes de sortie qui sont basées sur n’importe quelle information d’état agrégée dans process().

Cette méthode est appelée une fois pour chaque partition, après que toutes les lignes de cette partition ont été transmises à process().

Note

Si l’utilisateur ne partitionne pas les données explicitement, alors Snowflake partitionne les données implicitement. Pour plus de détails, voir : partitions.

Cette méthode peut produire zéro, une ou plusieurs lignes.

La méthode est facultative.

La méthode getOutputClass()

Cette méthode renvoie des informations sur la classe de ligne de sortie. La classe de ligne de sortie contient des informations sur les types de données de la ligne renvoyée.

La classe de ligne de sortie

Snowflake utilise la classe de ligne de sortie pour aider à spécifier les conversions entre les types de données Java et les types de données SQL.

Lorsqu’une UDTF Java renvoie une ligne, la valeur de chaque colonne de la ligne doit être convertie du type de données Java au type de données SQL correspondant. Les types de données SQL sont spécifiés dans la clause RETURNS de l’instruction CREATE FUNCTION. Toutefois, le mappage entre les types de données Java et SQL n’est pas de 1 pour 1, de sorte que Snowflake doit connaître le type de données Java pour chaque colonne renvoyée. (Pour plus d’informations sur le mappage de types de données SQL et Java, voir Mappages de type de donnée SQL-Java pour les paramètres et les types de retour).

Une UDTF Java spécifie les types de données Java des colonnes de sortie en définissant une classe de ligne de sortie. Chaque ligne renvoyée par l’UDTF est renvoyée comme une instance de la classe de ligne de sortie. Chaque instance de la classe de ligne de sortie contient un champ public pour chaque colonne de sortie. Snowflake lit les valeurs des champs publics de chaque instance de la classe de ligne de sortie, convertit les valeurs Java en valeurs SQL et construit une ligne de sortie SQL contenant ces valeurs.

Les valeurs de chaque instance de la classe de ligne de sortie sont définies en appelant le constructeur de la classe de ligne de sortie. Le constructeur accepte les paramètres qui correspondent aux colonnes de sortie, puis définit les champs publics en fonction de ces paramètres.

Le code ci-dessous définit un exemple de classe de ligne de sortie :

class OutputRow {

  public String name;
  public int id;

  public OutputRow(String pName, int pId) {
    this.name = pName;
    this.id = pId
  }

}

Les variables publiques spécifiées par cette classe doivent correspondre aux colonnes spécifiées dans la clause RETURNS TABLE (...) de l’instruction CREATE FUNCTION. Par exemple, la classe OutputRow ci-dessus correspond à la clause RETURNS ci-dessous :

CREATE FUNCTION F(...)
    RETURNS TABLE(NAME VARCHAR, ID INTEGER)
    ...

Important

La correspondance entre les noms des colonnes SQL et les noms des champs publics Java dans la classe de ligne de sortie n’est pas sensible à la casse. Par exemple, dans le code Java et SQL présenté ci-dessus, le champ Java nommé id correspond à la colonne SQL nommée ID.

La classe de lignes de sortie est utilisée comme suit :

  • La classe de gestion utilise la classe de ligne de sortie pour spécifier le type de retour de la méthode process() et de la méthode endPartition(). La classe de gestion utilise également la classe de ligne de sortie pour construire les valeurs retournées. Par exemple :

    public Stream<OutputRow> process(String v) {
      ...
      return Stream.of(new OutputRow(...));
    }
    
    public Stream<OutputRow> endPartition() {
      ...
      return Stream.of(new OutputRow(...));
    }
    
  • La classe de ligne de sortie est également utilisée dans la méthode getOutputClass() de la classe de gestion, qui est une méthode statique que Snowflake appelle afin d’apprendre les types de données Java des sorties :

    public static Class getOutputClass() {
      return OutputRow.class;
    }
    

Le déclenchement d’une exception à partir de n’importe quelle méthode de la classe de ligne de sortie (ou de la classe de gestion) entraîne l’arrêt du traitement. La requête qui a appelé l’UDTF échoue avec un message d’erreur.

Résumé des exigences

Le code Java de l’UDTF doit répondre aux exigences suivantes :

  • Le code doit définir une classe de ligne de sortie.

  • La classe de gestion de l’UDTF doit inclure une méthode publique nommée process() qui renvoie un flux <output_row_class>, où le flux (Stream) est défini dans java.util.stream.Stream.

  • La classe de gestion de l’UDTF doit définir une méthode statique publique nommée getOutputClass(), qui doit renvoyer <output_row_class>.class.

Si le code Java ne répond pas à ces exigences, la création ou l’exécution de l’UDTF échoue :

  • Si la session a un entrepôt actif au moment où l’instruction CREATE FUNCTION s’exécute, alors Snowflake détecte des violations lors de la création de la fonction.

  • Si la session n’a pas d’entrepôt actif au moment où l’instruction CREATE FUNCTION est exécutée, Snowflake détecte des violations lorsque la fonction est appelée.

Appel d’UDTF Java

Appelez une UDTF comme vous le feriez pour n’importe quelle fonction de table. Lorsque vous appelez une UDTF dans la clause FROM d’une requête, spécifiez le nom et les arguments de l’UDTF à l’intérieur des parenthèses qui suivent le mot-clé TABLE.

En d’autres termes, utilisez une forme telle que la suivante pour le mot-clé TABLE lorsque vous appelez une UDTF :

SELECT ...
  FROM TABLE ( udtf_name (udtf_arguments) )

Par exemple, l’instruction suivante appelle une fonction de table et lui transmet un littéral DATE :

select ...
  from table(my_java_udtf('2021-01-16'::DATE));

L’argument d’une fonction de table peut être une expression et pas seulement un littéral. Par exemple, une fonction de table peut être appelée en utilisant une colonne d’une table. Vous trouverez quelques exemples ci-dessous, notamment dans la section Exemples.

Pour plus d’informations sur les fonctions de table en général, voir fonction de table.

Fonctions et partitions des tables

Avant que les lignes ne soient transmises aux fonctions de table, les lignes peuvent être regroupées en partitions. Le partitionnement présente deux avantages principaux :

  • Il permet à Snowflake de diviser la charge de travail pour améliorer la parallélisation et donc les performances.

  • Le partitionnement permet à Snowflake de traiter toutes les lignes ayant une caractéristique commune comme un groupe. Vous pouvez renvoyer des résultats basés sur toutes les lignes d’un groupe, et pas seulement sur des lignes individuelles.

Par exemple, vous pouvez partitionner les données sur les cours des actions dans un groupe par action. Tous les prix des actions de chaque entreprise peuvent être analysés ensemble, tandis que les prix des actions de chaque entreprise peuvent être analysés indépendamment de toute autre entreprise.

Les données peuvent être partitionnées de manière explicite ou implicite.

Partitionnement explicite

Partitionnement explicite en plusieurs groupes

L’instruction suivante appelle les UDTF nommées my_udtf() sur des partitions individuelles. Chaque partition contient toutes les lignes pour lesquelles l’expression PARTITION BY donne la même valeur (par exemple, la même entreprise ou le même symbole boursier).

SELECT *
    FROM stocks_table AS st,
         TABLE(my_udtf(st.symbol, st.transaction_date, st.price) OVER (PARTITION BY st.symbol))

Partitionnement explicite en un seul groupe

L’instruction suivante appelle les UDTF nommées my_udtf() sur une seule partition. La clause PARTITION BY <constant> (dans ce cas PARTITION BY 1) place toutes les lignes dans la même partition.

SELECT *
    FROM stocks_table AS st,
         TABLE(my_udtf(st.symbol, st.transaction_date, st.price) OVER (PARTITION BY 1))

Pour un exemple plus complet et réaliste, voir Exemples d’appels d’UDTFs Java dans des requêtes, en particulier la sous-section intitulée Partition unique.

Tri des lignes pour les partitions

Pour traiter les lignes de chaque partition dans un ordre précis, incluez une clause ORDER BY. Cela indique à Snowflake de transmettre les lignes à la méthode de gestion par ligne dans l’ordre spécifié.

Par exemple, si vous souhaitez calculer la moyenne mobile du cours d’une action dans le temps, vous devez ordonner les cours de l’action par horodatage (ainsi que partitionner par symbole boursier). L’exemple suivant montre comment procéder :

SELECT *
     FROM stocks_table AS st,
          TABLE(my_udtf(st.symbol, st.transaction_date, st.price) OVER (PARTITION BY st.symbol ORDER BY st.transaction_date))

Une clause OVER peut contenir une clause ORDER BY même sans clause PARTITION BY.

N’oubliez pas qu’inclure une clause ORDER BY à l’intérieur d’une clause OVER () n’équivaut pas à placer une clause ORDER BY au niveau le plus externe de la requête. Si vous souhaitez que l’ensemble des résultats de la requête soit ordonné, vous devez utiliser une clause ORDER BY distincte. Par exemple :

SELECT *
    FROM stocks_table AS st,
         TABLE(my_udtf(st.symbol, st.transaction_date, st.price) OVER (PARTITION BY st.symbol ORDER BY st.transaction_date))
    ORDER BY st.symbol, st.transaction_date, st.transaction_time;

Notes sur l’utilisation du partitionnement explicite

Lorsqu’on utilise une UDTF avec une clause PARTITION BY , la clause PARTITION BY ne peut contenir qu’une référence de colonne ou un litéral, et non une expression générale. Par exemple, la commande suivante n’est pas autorisée :

SELECT * FROM udtf_table, TABLE(my_func(col1) OVER (PARTITION BY udtf_table.col2 * 2));   -- NO!

Partitionnement implicite

Si une fonction de table ne partitionne pas explicitement les lignes en utilisant une clause PARTITION BY, alors Snowflake partitionne généralement les lignes de manière implicite afin d’utiliser le traitement parallèle pour améliorer les performances.

Le nombre de partitions est généralement basé sur des facteurs tels que la taille de l’entrepôt qui traite la fonction et la cardinalité de la relation d’entrée. Les lignes sont généralement affectées à des partitions spécifiques sur la base de facteurs tels que l’emplacement physique des lignes (par exemple, par micropartition), de sorte que le regroupement n’a aucune signification.

Lors de l’exécution avec un partitionnement implicite, le code utilisateur ne peut faire aucune hypothèse sur les partitions. L’exécution sans partitionnement implicite est particulièrement utile lorsque l’UDTF n’a que besoin d’examiner les lignes en isolation pour produire sa sortie, et aucun état n’est agrégé d’une ligne à l’autre. Dans ce cas, le code n’a probablement pas besoin d’un constructeur ou d’une méthode endPartition().

Si l’UDF comprend une méthode finaliseur (par exemple, endPartition() pour des UDFs Java), le finaliseur est appelé sur chaque partition, que les données aient été partitionnées explicitement ou implicitement. Si les données ne sont pas partitionnées de manière significative, la sortie du finaliseur peut ne pas être significative.

Notes sur l’utilisation du partitionnement

  • Pour améliorer les performances, Snowflake exécute généralement plusieurs instances du code de gestion de l’UDTF en parallèle. Chaque partition de lignes est transmise à une seule instance de l’UDTF.

    Bien que chaque partition ne soit traitée que par une seule instance d’UDTF, l’inverse n’est pas nécessairement vrai – une seule instance d’UDTF peut traiter plusieurs partitions séquentiellement. Il est donc important d’utiliser l’initialiseur et le finaliseur pour initialiser et nettoyer chaque partition afin d’éviter de reporter les valeurs accumulées du traitement d’une partition au traitement d’une autre partition.

Exemples d’appels d’UDTFs Java dans des requêtes

Appel sans partitionnement explicite

Cet exemple montre comment créer une UDTF. Cet exemple renvoie deux copies de chaque entrée et renvoie une ligne supplémentaire pour chaque partition.

create function return_two_copies(v varchar)
returns table(output_value varchar)
language java
handler='TestFunction'
target_path='@~/TestFunction.jar'
as
$$

  import java.util.stream.Stream;

  class OutputRow {

    public String output_value;

    public OutputRow(String outputValue) {
      this.output_value = outputValue;
    }

  }


  class TestFunction {

    String myString;

    public TestFunction()  {
      myString = "Created in constructor and output from endPartition()";
    }

    public static Class getOutputClass() {
      return OutputRow.class;
    }

    public Stream<OutputRow> process(String inputValue) {
      // Return two rows with the same value.
      return Stream.of(new OutputRow(inputValue), new OutputRow(inputValue));
    }

    public Stream<OutputRow> endPartition() {
      // Returns the value we initialized in the constructor.
      return Stream.of(new OutputRow(myString));
    }

  }

$$;

Cet exemple montre comment appeler une UDTF. Pour que cet exemple reste simple, l’instruction transmet une valeur littérale plutôt qu’une colonne et omet la clause OVER().

SELECT output_value
   FROM TABLE(return_two_copies('Input string'));
+-------------------------------------------------------+
| OUTPUT_VALUE                                          |
|-------------------------------------------------------|
| Input string                                          |
| Input string                                          |
| Created in constructor and output from endPartition() |
+-------------------------------------------------------+

Cet exemple appelle l’UDTF avec des valeurs lues à partir d’une autre table. Chaque fois que la méthode process() est appelée, on lui transmet une valeur de la colonne city_name de la ligne actuelle de la table cities_of_interest. Comme ci-dessus, l’UDTF est appelée sans clause OVER() explicite.

Créez une table simple à utiliser comme source de données :

CREATE TABLE cities_of_interest (city_name VARCHAR);
INSERT INTO cities_of_interest (city_name) VALUES
    ('Toronto'),
    ('Warsaw'),
    ('Kyoto');

Appelez l’UDTF Java :

SELECT city_name, output_value
   FROM cities_of_interest,
       TABLE(return_two_copies(city_name))
   ORDER BY city_name, output_value;
+-----------+-------------------------------------------------------+
| CITY_NAME | OUTPUT_VALUE                                          |
|-----------+-------------------------------------------------------|
| Kyoto     | Kyoto                                                 |
| Kyoto     | Kyoto                                                 |
| Toronto   | Toronto                                               |
| Toronto   | Toronto                                               |
| Warsaw    | Warsaw                                                |
| Warsaw    | Warsaw                                                |
| NULL      | Created in constructor and output from endPartition() |
+-----------+-------------------------------------------------------+

Attention

Dans cet exemple, la syntaxe utilisée dans la clause FROM est identique à la syntaxe d’une jointure interne (c’est-à-dire FROM t1, t2) ; cependant, l’opération effectuée n’est pas une jointure interne vraie. Le comportement réel est que la fonction est appelée avec les valeurs de chaque ligne de la table. En d’autres termes, étant donné la clause FROM suivante :

from cities_of_interest, table(f(city_name))

le comportement serait équivalent au pseudo-code suivant :

for city_name in cities_of_interest:
    output_row = f(city_name)

La section d’exemples de la documentation des UDTFs JavaScript contient des exemples plus complexes de requêtes qui appellent des UDTFs avec des valeurs provenant de tables.

Si l’instruction ne spécifie pas explicitement le partitionnement, le moteur d’exécution Snowflake utilise le partitionnement implicite.

S’il n’y a qu’une seule partition, la méthode endPartition() n’est appelée qu’une seule fois et la sortie de la requête ne comprend qu’une seule ligne contenant la valeur Created in constructor and output from endPartition(). Si les données sont regroupées en un nombre différent de partitions lors des différentes exécutions de l’instruction, la méthode endPartition() est appelée un nombre différent de fois, et la sortie contient un nombre différent de copies de cette ligne.

Pour plus d’informations, voir partitionnement implicite.

Appel avec partitionnement explicite

Les UDTFs Java peuvent également être appelées en utilisant un partitionnement explicite.

Partitions multiples

L’exemple suivant utilise la même UDTF et la même table créées précédemment. L’exemple partitionne les données par nom de ville.

SELECT city_name, output_value
   FROM cities_of_interest,
       TABLE(return_two_copies(city_name) OVER (PARTITION BY city_name))
   ORDER BY city_name, output_value;
+-----------+-------------------------------------------------------+
| CITY_NAME | OUTPUT_VALUE                                          |
|-----------+-------------------------------------------------------|
| Kyoto     | Created in constructor and output from endPartition() |
| Kyoto     | Kyoto                                                 |
| Kyoto     | Kyoto                                                 |
| Toronto   | Created in constructor and output from endPartition() |
| Toronto   | Toronto                                               |
| Toronto   | Toronto                                               |
| Warsaw    | Created in constructor and output from endPartition() |
| Warsaw    | Warsaw                                                |
| Warsaw    | Warsaw                                                |
+-----------+-------------------------------------------------------+

Partition unique

L’exemple suivant utilise la même UDTF et la même table créées précédemment et partitionne les données par une constante, ce qui oblige Snowflake à n’utiliser qu’une seule partition :

SELECT city_name, output_value
   FROM cities_of_interest,
       TABLE(return_two_copies(city_name) OVER (PARTITION BY 1))
   ORDER BY city_name, output_value;
+-----------+-------------------------------------------------------+
| CITY_NAME | OUTPUT_VALUE                                          |
|-----------+-------------------------------------------------------|
| Kyoto     | Kyoto                                                 |
| Kyoto     | Kyoto                                                 |
| Toronto   | Toronto                                               |
| Toronto   | Toronto                                               |
| Warsaw    | Warsaw                                                |
| Warsaw    | Warsaw                                                |
| NULL      | Created in constructor and output from endPartition() |
+-----------+-------------------------------------------------------+

Notez que seule une copie du message Created in constructor and output from endPartition() a été incluse dans la sortie, ce qui indique que endPartition() n’a été appelé qu’une seule fois.

Traitement d’entrées très volumineuses (par exemple, des fichiers volumineux)

Dans certains cas, une UDTF nécessite une très grande quantité de mémoire pour traiter chaque ligne d’entrée. Par exemple, une UDTF peut lire et traiter un fichier trop volumineux pour tenir dans la mémoire.

Pour traiter des fichiers volumineux dans une UDF ou une UDTF, utilisez la classe SnowflakeFile ou InputStream. Pour plus d’informations, voir Traiter des données non structurées en utilisant des UDFs ou des UDTFs Java.

Utilisation d’une table ou d’une UDTF comme entrée d’une UDTF

L’entrée d’une fonction de table peut provenir d’une table ou d’une autre UDTF, comme documenté dans Utilisation d’une table comme entrée d’une fonction de table.

L’exemple ci-dessous montre comment utiliser une table pour fournir des entrées à l’UDTF Java splitFileIntoWords() :

create table file_names (file_name varchar);
insert into file_names (file_name) values ('sample.txt'),
                                          ('sample_2.txt');

select f.file_name, w.word
   from file_names as f, table(splitFileIntoWords(f.file_name)) as w;

La sortie devrait ressembler à ce qui suit :

+-------------------+------------+
| FILE_NAME         | WORD       |
+-------------------+------------+
| sample_data.txt   | some       |
| sample_data.txt   | words      |
| sample_data_2.txt | additional |
| sample_data_2.txt | words      |
+-------------------+------------+

La clause imports de l’UDTF Java doit spécifier le nom et le chemin d’accès de chaque fichier transmis à l’UDTF. Par exemple :

create function splitFileIntoWords(inputFileName string)
    ...
    imports = ('@inline_jars/sample.txt', '@inline_jars/sample_2.txt')
    ...

Chaque fichier doit déjà avoir été copié vers une zone de préparation (dans ce cas, la zone de préparation nommée @inline_jars) avant que l’UDTF ne lise le fichier.

Pour un exemple d’utilisation d’une UDTF comme entrée d’une autre UDTF, voir Exemples étendus utilisant les valeurs des tables et d’autres UDTFs comme entrées dans la documentation UDTF JavaScript.

Revenir au début