Si les fonctions intégrées de MaxCompute ne répondent pas à vos besoins, créez une fonction définie par l'utilisateur (UDF) en Java à l'aide d'un outil de développement tel qu'IntelliJ IDEA (Maven) ou Premiers pas avec MaxCompute Studio, puis appelez cette UDF dans des instructions SQL MaxCompute.
Limites
-
Accès à Internet via des UDF
Par défaut, MaxCompute n'autorise pas l'accès à Internet depuis les UDF. Pour y accéder, renseignez le formulaire de demande de connexion réseau selon vos exigences métier, puis envoyez la demande. L'équipe du support technique de MaxCompute vous contactera rapidement pour activer la connectivité réseau. Pour plus d'informations sur le remplissage de ce formulaire, consultez Processus de connexion réseau.
-
Accès à un VPC via des UDF
Par défaut, MaxCompute interdit aux UDF d'accéder aux ressources situées dans des VPC. Pour autoriser cet accès, établissez au préalable une connexion réseau entre MaxCompute et le VPC concerné. Pour plus d'informations sur les opérations associées, consultez Accéder aux ressources d'un VPC depuis une UDF.
-
Lecture de données de table via des UDF, UDAF ou UDTF
Les UDF, UDAF et UDTF ne permettent pas de lire les données des types de tables suivants :
Tables ayant subi une évolution de schéma
Tables contenant des types de données complexes
Tables contenant des types de données JSON
Tables transactionnelles
Remarques d'utilisation
Avant de rédiger une UDF en Java, familiarisez-vous avec la structure du code d'une UDF ainsi qu'avec les correspondances de types de données entre Java et MaxCompute. Pour plus d'informations, consultez Annexe : Types de données.
Lors de l'écriture d'une UDF en Java, tenez compte des points suivants :
Évitez d'inclure des classes portant le même nom mais implémentant des logiques différentes dans plusieurs fichiers JAR d'UDF. Par exemple, si UDF1 et UDF2 correspondent respectivement à udf1.jar et udf2.jar, et que ces deux fichiers JAR contiennent
com.aliyun.UserFunction.classavec des logiques distinctes, l'appel simultané des deux UDF dans une même instruction SQL amène MaxCompute à charger l'une des classes de manière aléatoire. Ce comportement peut entraîner des résultats inattendus ou un échec de compilation.Dans une UDF Java, les paramètres d'entrée et les valeurs de retour doivent utiliser des types objet (comme String et Long), et non des types primitifs (comme int et long).
Les valeurs NULL en SQL correspondent à NULL en Java. Les types primitifs Java ne pouvant pas représenter de valeurs NULL, leur utilisation est interdite.
Flux de développement d'une UDF
Le développement d'une UDF comprend plusieurs étapes : préparation de l'environnement, écriture du code, importation du fichier JAR, enregistrement de la fonction et débogage. Les sections suivantes illustrent ce flux de travail avec MaxCompute Studio, DataWorks et odpscmd.
Utilisation de MaxCompute Studio
L'exemple suivant montre comment développer et appeler, avec MaxCompute Studio, une UDF Java qui convertit des caractères en minuscules.
-
Préparez l'environnement.
Avant de développer et de déboguer une UDF dans MaxCompute Studio, installez MaxCompute Studio et connectez-le à un projet MaxCompute. Consultez les rubriques suivantes :
-
Rédigez le code de l'UDF.
Dans l'explorateur Project, cliquez avec le bouton droit sur le répertoire source du module () et sélectionnez .
-
Dans la boîte de dialogue Create new MaxCompute java class, cliquez sur UDF, saisissez un nom de classe dans le champ Name, puis appuyez sur Entrée.
Le champ Name définit le nom de la classe Java MaxCompute à créer. Si aucun package n'existe encore, saisissez packagename.classname pour en générer un automatiquement. Dans cet exemple, la classe s'appelle Lower.
-
Saisissez le code de l'UDF dans l'éditeur. Exemple :
package com.aliyun.odps.udf.example; import com.aliyun.odps.udf.UDF; public final class Lower extends UDF { public String evaluate(String s) { if (s == null) { return null; } return s.toLowerCase(); } }RemarquePour déboguer localement l'UDF Java, consultez Développer et déboguer des UDF.
-
Importez et enregistrez l'UDF.
Cliquez avec le bouton droit sur le fichier Java de l'UDF et sélectionnez Deploy to server.... Dans la boîte de dialogue Package a jar, submit resource and register function, configurez les paramètres et cliquez sur OK.
MaxCompute project : projet MaxCompute auquel appartient l'UDF. La fonction étant rédigée dans le projet MaxCompute déjà connecté, conservez la valeur par défaut.
Resource file : chemin du fichier de ressource dont dépend l'UDF. Conservez la valeur par défaut.
Resource name : ressource utilisée par l'UDF. Conservez la valeur par défaut.
Function name : nom employé pour appeler l'UDF dans les instructions SQL, par exemple Lower_test.
-
Déboguez l'UDF.
Dans le volet de navigation de gauche, cliquez sur Project Explore. Cliquez avec le bouton droit sur le projet MaxCompute cible et sélectionnez Open Console. Dans la console, saisissez l'instruction SQL appelant l'UDF et appuyez sur Entrée. Exemple :
select lower_test('ABC');Le résultat suivant s'affiche.
+-----+ | _c0 | +-----+ | abc | +-----+
Utilisation de DataWorks
-
Préparez l'environnement.
Avant de développer et de déboguer une UDF dans DataWorks, activez DataWorks et associez-y un projet MaxCompute. Pour plus d'informations, consultez Utiliser DataWorks.
-
Rédigez le code de l'UDF.
Tout outil de développement Java convient pour écrire le code de l'UDF et le conditionner dans un fichier JAR. Exemple :
package com.aliyun.odps.udf.example; import com.aliyun.odps.udf.UDF; public final class Lower extends UDF { public String evaluate(String s) { if (s == null) { return null; } return s.toLowerCase(); } } -
Importez et enregistrez l'UDF.
Importez le code conditionné dans DataWorks, puis enregistrez l'UDF. Consultez les rubriques suivantes :
-
Déboguez l'UDF.
Une fois l'UDF enregistrée, créez un nœud ODPS SQL et exécutez-y une instruction SQL afin de la déboguer. Pour savoir comment créer un nœud ODPS SQL, consultez Créer un nœud ODPS SQL. Exemple :
select lower_test('ABC');
Utilisation d'odpscmd
-
Préparez l'environnement.
Pour développer et déboguer une UDF avec odpscmd, installez le client et configurez sa connexion à un projet MaxCompute. Pour plus d'informations, consultez Utiliser le client MaxCompute (odpscmd).
-
Rédigez le code de l'UDF.
Tout outil de développement Java convient pour écrire le code de l'UDF et le conditionner dans un fichier JAR. Exemple :
package com.aliyun.odps.udf.example; import com.aliyun.odps.udf.UDF; public final class Lower extends UDF { public String evaluate(String s) { if (s == null) { return null; } return s.toLowerCase(); } } -
Importez et enregistrez l'UDF.
Importez le code conditionné via odpscmd, puis enregistrez l'UDF. Consultez les rubriques suivantes :
-
Déboguez l'UDF.
Après l'enregistrement de l'UDF, rédigez et exécutez une instruction SQL pour la déboguer. Exemple :
select lower_test('ABC');
Appel des UDF
Une fois l'UDF Java développée selon le flux de développement d'une UDF, appelez-la dans MaxCompute SQL. Deux méthodes s'offrent à vous :
Utilisation d'une UDF dans un projet MaxCompute : cette méthode s'apparente à celle des fonctions intégrées. Une fonction définie par l'utilisateur s'emploie exactement comme une fonction intégrée.
Utilisation d'une UDF entre projets : exploitez une UDF du projet B depuis le projet A. L'instruction suivante fournit un exemple :
select B:udf_in_other_project(arg0, arg1) as res from table_t;. Pour plus d'informations sur le partage interprojets, consultez Accès aux ressources interprojets basé sur les packages.
Exemples d'UDF
Annexe : Structure du code d'une UDF
Une UDF Java se compose des éléments suivants :
-
Package Java : facultatif.
Regroupez vos classes Java dans un package afin de faciliter leur réutilisation et leur organisation.
-
Héritage de la classe UDF : obligatoire.
La classe de base requise est
com.aliyun.odps.udf.UDF. Si vous avez besoin d'autres classes UDF ou de types de données complexes, ajoutez les classes nécessaires depuis le SDK MaxCompute. Par exemple, la classe correspondant au type de données STRUCT estcom.aliyun.odps.data.Struct. -
Annotation
@Resolve: facultative.Son format est
@Resolve(<signature>), oùsignaturedéfinit les types de données des paramètres d'entrée et de la valeur de retour. Lorsqu'une UDF utilise le type de données STRUCT, la réflexion ne permet pas de récupérer les noms et les types des champs depuiscom.aliyun.odps.data.Struct. Dans ce cas, recourez à l'annotation@Resolvepour les obtenir. Si votre UDF manipule le type STRUCT, ajoutez l'annotation@Resolveà la classe de l'UDF. Cette annotation n'affecte que les surcharges dont les paramètres ou les valeurs de retour contiennent com.aliyun.odps.data.Struct. Exemple :@Resolve("struct<a:string>,string->string"). Pour un exemple détaillé, consultez Exemple d'UDF : types de données complexes. -
Classe Java personnalisée : obligatoire.
Cette unité structure le code de votre UDF et définit les variables ainsi que les méthodes qui mettent en œuvre votre logique métier.
-
Méthode
evaluate: obligatoire.Votre classe Java personnalisée doit inclure une méthode
evaluatepublique et non statique. Les types de données de ses paramètres d'entrée et de sa valeur de retour déterminent la signature SQL de l'UDF.Plusieurs méthodes
evaluatepeuvent coexister. Lors de l'appel de l'UDF, MaxCompute sélectionne la méthodeevaluatecorrespondant aux types des arguments fournis.Lors de la rédaction d'une UDF Java, utilisez indifféremment des types Java ou des types Java Writable. Pour connaître les correspondances détaillées entre les types de données MaxCompute et Java, consultez Annexe : Types de données.
Initialisation et nettoyage de l'UDF : facultatifs. Mettez-les en œuvre à l'aide de
void setup(ExecutionContext ctx)etvoid close(). La méthodevoid setup(ExecutionContext ctx)s'exécute une seule fois avant la méthodeevaluate; elle sert à initialiser les ressources ou les objets membres nécessaires au calcul. Quant à la méthodevoid close(), elle intervient une fois après l'ensemble des appels àevaluateet prend en charge les tâches de nettoyage, comme la fermeture des fichiers.
Les exemples suivants illustrent deux catégories d'UDF.
-
Avec des types Java
// Organize the Java class in the org.alidata.odps.udf.examples package. package org.alidata.odps.udf.examples; // Inherit the UDF class. import com.aliyun.odps.udf.UDF; // Define a custom Java class. public final class Lower extends UDF { // The evaluate method defines the UDF's logic. It takes a String and returns a String. public String evaluate(String s) { if (s == null) { return null; } return s.toLowerCase(); } } -
Avec des types Java Writable
// Organize the Java class in the com.aliyun.odps.udf.example package. package com.aliyun.odps.udf.example; // Add the required classes for the Java Writable type. import com.aliyun.odps.io.Text; // Inherit the UDF class. import com.aliyun.odps.udf.UDF; // Define a custom Java class. public class MyConcat extends UDF { private Text ret = new Text(); // Define the evaluate method. `Text` specifies the data type of the input parameters, and the `return` value is also a Text object. public Text evaluate(Text a, Text b) { if (a == null || b == null) { return null; } ret.clear(); ret.append(a.getBytes(), 0, a.getLength()); ret.append(b.getBytes(), 0, b.getLength()); return ret; } }
MaxCompute prend également en charge les UDF développées pour sa version compatible Hive. Pour plus d'informations, consultez Compatibilité des UDF Hive.
Annexe : Types de données
Correspondances des types de données
Pour garantir la cohérence entre les types utilisés dans une UDF Java et ceux de MaxCompute, appliquez les correspondances suivantes.
Les types de données pris en charge par MaxCompute varient selon l'édition choisie. Depuis MaxCompute 2.0, des types supplémentaires sont disponibles, notamment les types complexes tels que ARRAY, MAP et STRUCT. Pour plus d'informations, consultez Éditions de types de données.
|
Type MaxCompute |
Type Java |
Type Java Writable |
|
TINYINT |
java.lang.Byte |
ByteWritable |
|
SMALLINT |
java.lang.Short |
ShortWritable |
|
INT |
java.lang.Integer |
IntWritable |
|
BIGINT |
java.lang.Long |
LongWritable |
|
FLOAT |
java.lang.Float |
FloatWritable |
|
DOUBLE |
java.lang.Double |
DoubleWritable |
|
DECIMAL |
java.math.BigDecimal |
BigDecimalWritable |
|
BOOLEAN |
java.lang.Boolean |
BooleanWritable |
|
STRING |
java.lang.String |
Text |
|
VARCHAR |
com.aliyun.odps.data.Varchar |
VarcharWritable |
|
BINARY |
com.aliyun.odps.data.Binary |
BytesWritable |
|
DATE |
java.sql.Date |
DateWritable |
|
DATETIME |
java.util.Date |
DatetimeWritable |
|
TIMESTAMP |
java.sql.Timestamp |
TimestampWritable |
|
INTERVAL_YEAR_MONTH |
N/A |
IntervalYearMonthWritable |
|
INTERVAL_DAY_TIME |
N/A |
IntervalDayTimeWritable |
|
ARRAY |
java.util.List |
N/A |
|
MAP |
java.util.Map |
N/A |
|
STRUCT |
com.aliyun.odps.data.Struct |
N/A |
Le type Java byte[] ne figure pas parmi les types Java pris en charge. Si vous utilisez byte[] comme paramètre d'entrée ou valeur de retour d'une méthode evaluate, l'erreur ODPS-0130071 est signalée. Pour traiter des données binaires dans une UDF, employez les types Java correspondant au type BINARY de MaxCompute : com.aliyun.odps.data.Binary pour le type Java standard, ou com.aliyun.odps.io.BytesWritable pour le type Writable. Vous pouvez également convertir les données binaires en chaîne encodée en Base64 et utiliser le type String comme valeur de retour.
Compatibilité des UDF Hive
Si votre projet MaxCompute utilise l'édition de types de données 2,0, MaxCompute prend en charge les UDF de style Hive. Vous pouvez ainsi employer directement les UDF Hive développées pour une version compatible de Hive.
La version compatible de Hive est la 2.1.0, qui correspond à Hadoop 2.7.2. Si votre UDF a été compilée avec une autre version de Hive ou de Hadoop, recompilez le fichier JAR de l'UDF sous Hive 2.1.0 ou Hadoop 2.7.2.
Pour un exemple détaillé d'utilisation d'une UDF Hive dans MaxCompute, consultez Exemple d'UDF : compatibilité Hive.