Tous les produits
Search
Centre de documentation

MaxCompute:Vue d'ensemble des UDT

Dernière mise à jour :Aug 10, 2026

MaxCompute introduit les types définis par l'utilisateur (UDT) basés sur le moteur SQL de nouvelle génération. Les UDT vous permettent de référencer des classes ou des objets de langages de programmation tiers dans des instructions SQL pour appeler des méthodes ou récupérer des données.

Quand utiliser les UDT plutôt que les UDF ?

Les UDT et les fonctions définies par l'utilisateur (UDF) étendent toutes deux MaxCompute SQL avec une logique personnalisée. Le choix dépend de votre flux de travail :

Situation Approche recommandée
Appeler directement une méthode de classe Java intégrée (par exemple, Integer.MAX_VALUE) UDT — aucune définition de fonction n'est requise
Réutiliser directement une bibliothèque tierce dans une expression SQL UDT — référencez la classe en ligne sans encapsulation
Inclure des objets compilés de langage source dans des travaux en plusieurs étapes UDT — encapsule automatiquement l'état JVM entre les étapes
Implémenter une logique métier réutilisable dans plusieurs projets UDF — l'enregistrement explicite de la fonction permet son partage

Cas d'utilisation

  • Appeler des méthodes de la bibliothèque standard Java sans définir de fonction. Lorsqu'une tâche nécessite une méthode de classe Java intégrée que MaxCompute SQL n'expose pas nativement, un UDT vous permet de l'appeler directement dans une expression.

  • Référencer des bibliothèques tierces en ligne. Au lieu d'encapsuler une fonction de bibliothèque tierce dans une UDF, référencez la classe directement dans une instruction SQL.

  • Intégrer du code source compilé dans SQL. Pour les langages comme Java qui nécessitent une compilation, les UDT vous permettent de référencer des objets et des classes dans des expressions SQL sans étape d'enregistrement distincte. Consultez SELECT TRANSFORM pour découvrir les alternatives basées sur des scripts.

Prérequis

Avant d'utiliser les UDT, assurez-vous que :

  • Le JDK 1.8 est disponible dans votre environnement. Les versions ultérieures au JDK 1.8 peuvent ne pas être prises en charge.

  • Les nouveaux types de données sont activés si vous utilisez des types tels que INT : set odps.sql.type.system.odps2=true;

Fonctionnement

Contrairement aux UDT d'autres moteurs SQL (qui définissent généralement des alias de type similaires au type STRUCT), les UDT MaxCompute fonctionnent comme une instruction CREATE TYPE : ils contiennent à la fois des champs et des méthodes, et vous les référencez directement dans SQL sans écrire de DDL.

L'exemple suivant illustre cette différence. Pour accéder à Integer.MAX_VALUE depuis le package java.lang de Java :

Utilisation d'un UDT (référence directe) :

-- Enable new data types (required for types such as INTEGER).
set odps.sql.type.system.odps2=true;
SELECT java.lang.Integer.MAX_VALUE;

Étant donné que java.lang est importé automatiquement (comme en Java), cela équivaut à :

set odps.sql.type.system.odps2=true;
SELECT Integer.MAX_VALUE;

Résultat :

+-----------+
| max_value |
+-----------+
| 2147483647 |
+-----------+

Utilisation d'une UDF (à titre de comparaison) :

  1. Rédigez la classe UDF :

    package com.aliyun.odps.test;
    public class IntegerMaxValue extends com.aliyun.odps.udf.UDF {
      public Integer evaluate() {
         return Integer.MAX_VALUE;
      }
    }
  2. Compilez, téléchargez et enregistrez :

    add jar odps-test.jar;
    create function integer_max_value as 'com.aliyun.odps.test.IntegerMaxValue' using 'odps-test.jar';
  3. Appelez la fonction :

    select integer_max_value();

Les UDT permettent de réduire cette procédure à une seule instruction SQL.

Exécution en plusieurs étapes

Les objets UDT circulent naturellement entre les étapes MapReduce. L'exemple suivant joint deux colonnes BigInteger calculées à partir de sources de données différentes :

-- Sample data.
@table1 := select * from values ('100000000000000000000') as t(x);
@table2 := select * from values (100L) as t(y);

-- Create an object with the new method.
@a := select new java.math.BigInteger(x) x from @table1;
-- Call a static method.
@b := select java.math.BigInteger.valueOf(y) y from @table2;
-- Call an instance method across the join.
select /*+mapjoin(b)*/ x.add(y).toString() from @a a join @b b;

-- Output:
100000000000000000100

Ce travail s'exécute en trois étapes (M1, R2, J3). new java.math.BigInteger(x) s'exécute lors de l'étape M1 ; java.math.BigInteger.valueOf(y) et x.add(y).toString() s'exécutent lors de l'étape J3 sur des processus et des machines physiques différents. Le UDT encapsule ce fonctionnement de sorte que toutes les étapes se comportent comme si elles s'exécutaient sur la même machine virtuelle Java (JVM).

Le DAG de ce travail SQL utilisant des UDT contient trois étapes : M1R2_1J3_2. Toutes les étapes sont terminées à 100 %, avec 1 ligne de données transmise entre chaque étape.

La colonne x de la variable a est de type java.math.BigInteger plutôt qu'un type intégré. Cette valeur UDT peut être transmise à d'autres opérateurs et utilisée lors du brassage des données.

Référence des packages JAR et configuration des imports Java

Toutes les classes du SDK pour Java sont disponibles par défaut pour les UDT. Pour référencer des packages JAR supplémentaires ou définir des chemins d'importation par défaut, utilisez les indicateurs de session suivants.

Référencer un package JAR :

set odps.sql.type.system.odps2=true;
set odps.sql.session.resources=odps-test.jar;
-- The JAR must be uploaded to the project beforehand.
select new com.aliyun.odps.test.IntegerMaxValue().evaluate();

Vous pouvez spécifier plusieurs ressources séparées par des virgules : set odps.sql.session.resources=foo.sh,bar.txt;

odps.sql.session.resources contrôle à la fois les UDT et SELECT TRANSFORM. Un JAR défini ici est disponible pour les deux fonctionnalités.

Définir un chemin d'importation Java par défaut :

set odps.sql.type.system.odps2=true;
set odps.sql.session.resources=odps-test.jar;
set odps.sql.session.java.imports=com.aliyun.odps.test.*;
-- With the import set, you can omit the full package prefix.
select new IntegerMaxValue().evaluate();

odps.sql.session.java.imports accepte un classpath (par exemple, java.math.BigInteger) ou un caractère générique (*). Les imports statiques ne sont pas pris en charge.

Opérations prises en charge

Les UDT prennent en charge les opérations suivantes dans les expressions SQL :

  • Créer des objets à l'aide de new — exemple : new java.math.BigInteger('123')

  • Créer des tableaux à l'aide de new avec des listes d'initialisation — exemple : new Integer[] { 1, 2, 3 }

  • Appeler des méthodes d'instance et statiques

  • Accéder aux champs d'instance et statiques publics

Seules les méthodes publiques et les champs publics sont accessibles. Tous les identifiants (noms de package, noms de classe, noms de méthode, noms de champ) sont sensibles à la casse. Les classes anonymes et les expressions lambda ne sont pas prises en charge. Les fonctions qui ne renvoient pas de valeurs ne peuvent pas être appelées dans des expressions.

Types de données

Mappage des types

Les types de données Java correspondent aux types intégrés de MaxCompute. Le même mappage utilisé dans les UDF Java s'applique aux UDT.

  • Appelez directement les méthodes des types intégrés : '123'.length(), 1L.hashCode()

  • Utilisez les UDT dans les fonctions intégrées : chr(Long.valueOf('100'))Long.valueOf renvoie java.lang.Long, qui correspond au type intégré BIGINT

  • Les types primitifs Java sont automatiquement convertis en leurs types d'encapsulation (boxing)

Pour les nouveaux types de données intégrés, ajoutez set odps.sql.type.system.odps2=true; avant d'exécuter la requête.

Conversions de types

  • Les conversions de type SQL sont prises en charge : cast(1 as java.lang.Object)

  • Les casts de style Java ne sont pas pris en charge : (Object)1

  • Les objets UDT peuvent être implicitement convertis en objets de classe de base

  • Les objets UDT peuvent être explicitement convertis (cast) en objets de classe de base ou de sous-classe

  • La conversion entre deux types non apparentés suit les mêmes règles que la conversion des types intégrés. Par exemple, la conversion de java.lang.Long en java.lang.Integer applique les mêmes règles que la conversion de BIGINT en INT, ce qui peut entraîner une perte de données.

Les objets UDT ne peuvent pas être enregistrés sur disque ni insérés directement dans des tables (le DDL ne prend pas en charge les UDT comme type de colonne). Si la valeur UDT peut être implicitement convertie en un type intégré, elle peut être écrite dans une table. Le type BINARY prend en charge la sérialisation automatique : les tableaux byte[] peuvent être enregistrés et désérialisés. Pour persister un UDT, convertissez-le en BINARY à l'aide de méthodes de sérialisation et de désérialisation. Les valeurs UDT ne peuvent pas apparaître directement dans la sortie finale. Appelez toString() pour convertir n'importe quel UDT en java.lang.String afin de l'afficher. Pour convertir automatiquement toutes les sorties UDT en chaînes lors du débogage, utilisez : Cet indicateur s'applique uniquement aux instructions PRINT, pas aux instructions INSERT.
set odps.sql.udt.display.tostring=true;

Génériques

Les UDT prennent en charge les génériques Java. Le compilateur déduit le paramètre de type à partir de l'argument :

-- Returns java.util.List<java.math.BigInteger>
java.util.Arrays.asList(new java.math.BigInteger('1'))

Spécifiez explicitement les paramètres de type dans les appels de constructeur ou utilisez java.lang.Object :

-- ArrayList<Object>
new java.util.ArrayList(java.util.Arrays.asList('1', '2'))

-- ArrayList<String>
new java.util.ArrayList<String>(java.util.Arrays.asList('1', '2'))

Sémantique des opérateurs

Tous les opérateurs suivent la sémantique de MaxCompute SQL, et non celle de Java :

  • Concaténation de chaînes : String.valueOf(1) + String.valueOf(2) renvoie 3 (les deux chaînes sont implicitement converties en DOUBLE et additionnées). Pour concaténer sous forme de chaînes, utilisez plutôt une fonction de concaténation de chaînes.

  • Égalité : L'opérateur = est un opérateur de comparaison SQL, et non une égalité de référence Java. Utilisez la méthode equals pour vérifier si deux objets sont équivalents.

Égalité des objets et brassage des données

Les UDT n'ont pas de définition claire de l'égalité des objets. Lors du brassage des données, les objets peuvent être transmis entre des processus et des machines physiques, ce qui fait qu'un seul objet apparaît comme deux références distinctes. Utilisez toujours la méthode equals — et non = — pour comparer les objets UDT.

Les objets au sein d'une même ligne ou colonne sont corrélés, mais la corrélation entre les lignes ou les colonnes n'est pas garantie.

Limitations

Les UDT ne peuvent pas être utilisés comme clés de brassage dans les clauses JOIN, GROUP BY, DISTRIBUTE BY, SORT BY, ORDER BY ou CLUSTER BY . Les UDT sont valides dans les expressions à ces étapes, mais ne peuvent pas constituer la sortie. Par exemple :

  • group by new java.math.BigInteger('123') — non pris en charge

  • group by new java.math.BigInteger('123').hashCode() — pris en charge, car hashCode() renvoie int.class, qui correspond au type intégré INT

Les UDF, les fonctions d'agrégation définies par l'utilisateur (UDAF) et les UDT ne peuvent pas lire les données des types de tables suivants :

  • Tables sur lesquelles une évolution de schéma est effectuée

  • Tables contenant des types de données complexes

  • Tables contenant des types de données JSON

  • Tables transactionnelles

Accès aux ressources

Dans MaxCompute SQL, appelez la méthode statique com.aliyun.odps.udf.impl.UDTExecutionContext.get() pour obtenir l'objet ExecutionContext . Utilisez cet objet pour accéder au contexte d'exécution actuel, y compris les fichiers et les tables enregistrés en tant que ressources.

Considérations relatives aux performances

Les performances des UDT sont similaires à celles des UDF. Le moteur de calcul optimisé offre des améliorations supplémentaires dans des scénarios spécifiques :

  • Aucune surcharge de sérialisation pour les opérations locales. Lorsqu'un objet UDT est utilisé au sein du même processus (aucun brassage de données requis, comme dans les étapes JOIN ou AGGREGATE), la sérialisation et la désérialisation sont ignorées.

  • Exécution basée sur Codegen. Les UDT s'exécutent via Codegen plutôt que par réflexion, il n'y a donc aucune surcharge liée à la réflexion. Plusieurs appels UDT sont regroupés en un seul appel de fonction — par exemple, values[x].add(values[y]).divide(java.math.BigInteger.valueOf(2)) est appelé une seule fois, évitant ainsi la surcharge d'interface par appel.

Sécurité

Les UDT sont soumis au même modèle de sandbox Java que les UDF. Pour effectuer des opérations restreintes par la sandbox, annulez l'isolation de la sandbox pour ces opérations ou faites une demande pour rejoindre la liste blanche de la sandbox.

Fonctionnalités à améliorer

Les fonctionnalités suivantes sont prévues pour les versions futures :

  • Appeler des fonctions qui ne renvoient pas de valeurs, et des fonctions qui utilisent directement des données transférées (où la valeur de retour est ignorée, comme la méthode add de l'interface List).

  • Utiliser des classes anonymes et des expressions lambda.

  • Utiliser les UDT comme clés de brassage.

  • Prendre en charge davantage de langages de programmation, tels que Python.

Étapes suivantes