MaxCompute prend en charge le développement de fonctions définies par l'utilisateur (UDF) en Python 3 pour implémenter une logique métier personnalisée.
Structure du code UDF
Vous pouvez utiliser MaxCompute Studio pour écrire une UDF en Python 3. Le code doit contenir les éléments suivants :
-
Importation de module : obligatoire.
Le code UDF doit inclure
from odps.udf import annotate, qui sert à importer la signature de fonction. Ainsi, MaxCompute peut identifier la signature de fonction définie dans le code. Si vous souhaitez référencer des fichiers ou des tables dans le code UDF, celui-ci doit inclurefrom odps.distcache import get_cache_fileoufrom odps.distcache import get_cache_table. -
Signature de fonction : obligatoire.
Le format est
@annotate(<signature>), oùsignaturedéfinit les types de données des paramètres d'entrée et de la valeur de retour de la fonction. Pour plus d'informations sur les signatures de fonction, consultez la section Signatures de fonction et types de données. -
Classe Python personnalisée : obligatoire.
La classe organise votre code UDF et définit les variables et méthodes qui implémentent votre logique métier. Vous pouvez également référencer une bibliothèque tierce intégrée ou des ressources de fichier et de table dans votre code. Pour plus d'informations, consultez les sections Bibliothèque tierce ou Ressources de référence.
-
Méthode
evaluate: obligatoire.La méthode evaluate est contenue dans la classe Python personnalisée. La méthode
evaluatedéfinit les paramètres d'entrée et la valeur de retour de l'UDF. Chaque classe Python ne peut contenir qu'une seule méthodeevaluate.
L'exemple de code suivant illustre une UDF.
# Import the function signature module.
from odps.udf import annotate
# Define the function signature.
@annotate("bigint,bigint->bigint")
# Define the custom Python class.
class MyPlus(object):
# Implement the evaluate method.
def evaluate(self, arg0, arg1):
if None in (arg0, arg1):
return None
return arg0 + arg1
Limites
-
Accès à Internet via les UDF
Par défaut, MaxCompute n'autorise pas l'accès à Internet via les UDF. Si vous souhaitez accéder à Internet via des UDF, remplissez le formulaire de demande de connexion réseau en fonction de vos besoins métier et soumettez la demande. L'équipe d'assistance technique MaxCompute vous contactera rapidement pour activer la connectivité réseau. Pour plus d'informations sur la manière de remplir le formulaire de demande de connexion réseau, consultez la rubrique Processus de connexion réseau.
-
Accès à un VPC via les UDF
Par défaut, MaxCompute n'autorise pas l'accès aux ressources des VPC via les UDF. Pour utiliser des UDF afin d'accéder aux ressources d'un VPC, vous devez établir une connexion réseau entre MaxCompute et le VPC. Pour plus d'informations sur les opérations associées, consultez la rubrique Accéder aux ressources VPC depuis une UDF.
-
Lecture des données de table via des UDF, UDAF ou UDTF
Vous ne pouvez pas utiliser des UDF, UDAF ou UDTF pour lire les données des types de tables suivants :
Table sur laquelle une évolution de schéma est effectuée
Table contenant des types de données complexes
Table contenant des types de données JSON
Table transactionnelle
Remarques sur l'utilisation
Python 3 n'est pas compatible avec Python 2 et les deux ne peuvent pas être utilisés dans la même instruction SQL. Tenez compte de la compatibilité avant d'effectuer la migration.
Python 2 a atteint sa fin de vie (EOL) au début de l'année 2020. Nous vous recommandons de migrer vos projets en fonction de leur type.
Développement de fonctions définies par l'utilisateur (UDF) : flux de travail général
Le développement d'une UDF comprend la préparation de l'environnement, la rédaction du code, le chargement et l'enregistrement de la fonction, puis son appel. Les sections suivantes décrivent ce flux de travail à l'aide de MaxCompute Studio, DataWorks et odpscmd.
MaxCompute Studio
-
Prérequis
Installez MaxCompute Studio et connectez-le à un projet MaxCompute avant de commencer. Pour plus d'informations, consultez les rubriques suivantes :
-
Rédigez le code de la UDF.
Dans le panneau Project, sous le répertoire MaxCompute Studio, cliquez avec le bouton droit sur scripts, puis sélectionnez .
Dans la boîte de dialogue Create new MaxCompute python class, saisissez un nom de classe dans le champ Name, sélectionnez Python UDF comme type, puis cliquez sur OK.
-
Rédigez le code de la UDF dans l'éditeur.
from odps.udf import annotate @annotate("string,bigint->string") class GetUrlChar(object): def evaluate(self, url, n): if n == 0: return "" try: index = url.find(".htm") if index < 0: return "" a = url[:index] index = a.rfind("/") b = a[index + 1:] c = b.split("-") if len(c) < n: return "" return c[-n] except Exception: return "Internal error"RemarquePour savoir comment déboguer localement des UDF Python, consultez la rubrique Tester une UDF.
-
Chargez et enregistrez la UDF.
Cliquez avec le bouton droit sur le programme Python cible et sélectionnez Deploy to server…. Configurez le nom de la fonction, puis cliquez sur OK. Pour plus d'informations, consultez la rubrique Charger un fichier et enregistrer une fonction.
Dans cet exemple, le nom de la fonction est défini sur UDF_GET_URL_CHAR.
-
Appelez la fonction UDF.
Dans le volet de navigation de gauche, cliquez sur Project Explore. Cliquez avec le bouton droit sur le projet MaxCompute cible, sélectionnez Open Console, puis saisissez et exécutez l'instruction SQL pour appeler la fonction UDF.
SET odps.sql.python.version=cp37; -- This command is required to enable Python 3 for the UDF. SELECT UDF_GET_URL_CHAR("http://www.taobao.com/a.htm", 1);Le résultat suivant est renvoyé :
+-----+ | _c0 | +-----+ | a | +-----+
DataWorks
-
Prérequis
Activez DataWorks et associez-le à un projet MaxCompute avant de commencer. Pour plus d'informations, consultez la rubrique Connect to MaxCompute by using DataWorks.
-
Écrivez le code de la fonction UDF.
Vous pouvez développer le code de la fonction UDF dans n'importe quel outil de développement Python et l'empaqueter. Le code ci-dessous constitue un exemple.
from odps.udf import annotate @annotate("string,bigint->string") class GetUrlChar(object): def evaluate(self, url, n): if n == 0: return "" try: index = url.find(".htm") if index < 0: return "" a = url[:index] index = a.rfind("/") b = a[index + 1:] c = b.split("-") if len(c) < n: return "" return c[-n] except Exception: return "Internal error" -
Téléchargez et enregistrez la fonction UDF.
Téléchargez le code empaqueté et enregistrez la fonction UDF dans DataWorks. Pour plus d'informations, consultez les rubriques suivantes :
-
Appelez la fonction UDF.
Une fois la fonction UDF enregistrée, créez un nœud ODPS SQL pour écrire et exécuter des instructions SQL qui appellent cette fonction. Pour plus d'informations sur les nœuds ODPS SQL, consultez la rubrique Develop an ODPS SQL task. L'exemple de code suivant illustre l'instruction SQL.
SET odps.sql.python.version=cp37; -- This command is required to enable Python 3 for the UDF. SELECT UDF_GET_URL_CHAR("http://www.taobao.com/a.htm", 1);
odpscmd
-
Prérequis
Téléchargez et installez odpscmd, puis configurez le fichier de configuration pour vous connecter à un projet MaxCompute. Pour plus d'informations, consultez la rubrique Connect by using the MaxCompute client (odpscmd).
-
Écrivez le code de la fonction UDF.
Vous pouvez développer le code de la fonction UDF dans n'importe quel outil de développement Python et l'empaqueter. Le code ci-dessous constitue un exemple.
from odps.udf import annotate @annotate("string,bigint->string") class GetUrlChar(object): def evaluate(self, url, n): if n == 0: return "" try: index = url.find(".htm") if index < 0: return "" a = url[:index] index = a.rfind("/") b = a[index + 1:] c = b.split("-") if len(c) < n: return "" return c[-n] except Exception: return "Internal error" -
Téléchargez et enregistrez la fonction UDF.
Téléchargez le code empaqueté et enregistrez la fonction UDF à l'aide d'odpscmd. Pour plus d'informations, consultez les rubriques suivantes :
-
Appelez la fonction UDF.
Une fois la fonction UDF enregistrée, écrivez et exécutez une instruction SQL pour l'appeler.
SET odps.sql.python.version=cp37; -- This command is required to enable Python 3 for the UDF. SELECT UDF_GET_URL_CHAR("http://www.taobao.com/a.htm", 1);
Installation de la bibliothèque NumPy
L'environnement d'exécution Python 3 intégré n'inclut pas NumPy. Si votre fonction UDF nécessite NumPy, téléchargez manuellement le package WHEEL. Lorsque vous téléchargez le package depuis PyPI ou un site miroir, le nom du fichier suit le format numpy-<version>-cp37-cp37m-manylinux1_x86_64.whl. Pour plus d'informations sur le téléchargement d'un package, consultez les rubriques Resource operations ou Use a third-party package in a Python UDF.
Pour obtenir la liste des bibliothèques standard prises en charge par Python 3, consultez la documentation relative à la bibliothèque standard Python 3.
Signatures de fonction et types de données
Format des signatures de fonction :
@annotate(<signature>)
Le paramètre signature est une chaîne qui spécifie les types de données des paramètres d'entrée et de la valeur de retour. Lors de l'exécution d'une UDF, les types de données des paramètres d'entrée et de la valeur de retour doivent correspondre à ceux indiqués dans la signature de la fonction. La cohérence des types de données est vérifiée lors de l'analyse sémantique. En cas d'incohérence, une erreur est renvoyée. Format d'une signature :
'arg_type_list -> type'
description des paramètres :
-
arg_type_list: spécifie les types de données des paramètres d'entrée. Si plusieurs paramètres d'entrée sont utilisés, leurs types de données sont séparés par des virgules (,). Les types de données suivants sont pris en charge : BIGINT, STRING, DOUBLE, BOOLEAN, DATETIME, DECIMAL, FLOAT, BINARY, DATE, DECIMAL(precision,scale), CHAR et VARCHAR. Les types de données complexes, tels que ARRAY, MAP et STRUCT, ainsi que les types de données complexes imbriqués, sont également pris en charge.Le paramètre
arg_type_listpeut être représenté par un astérisque (*) ou laissé vide ('').Si
arg_type_listest représenté par un astérisque (*), un nombre aléatoire de paramètres d'entrée est autorisé.Si
arg_type_listest laissé vide (''), aucun paramètre d'entrée n'est utilisé.
type: spécifie le type de données de la valeur de retour. Pour une UDF, une seule colonne de valeurs est renvoyée. Les types de données suivants sont pris en charge : BIGINT, STRING, DOUBLE, BOOLEAN, DATETIME, DECIMAL, FLOAT, BINARY, DATE et DECIMAL(precision,scale). Les types de données complexes, tels que ARRAY, MAP et STRUCT, ainsi que les types de données complexes imbriqués, sont également pris en charge.
Lors de l'écriture du code UDF, vous pouvez sélectionner un type de données en fonction de l'édition des types de données MaxCompute utilisée par votre projet MaxCompute. Pour plus d'informations sur les éditions des types de données MaxCompute et les types de données pris en charge dans chaque édition, consultez Éditions des types de données.
Le tableau suivant présente des exemples de signatures de fonction valides.
|
Signature de fonction |
Description |
|
|
Les types de données des paramètres d'entrée sont BIGINT et DOUBLE et le type de données de la valeur de retour est STRING. |
|
|
Un nombre aléatoire de paramètres d'entrée est utilisé et le type de données de la valeur de retour est STRING. |
|
|
Aucun paramètre d'entrée n'est utilisé et le type de données de la valeur de retour est DOUBLE. |
|
|
Le type de données des paramètres d'entrée est ARRAY<BIGINT> et le type de données de la valeur de retour est STRUCT<x:STRING, y:INT>. |
|
|
Aucun paramètre d'entrée n'est utilisé et le type de données de la valeur de retour est MAP<BIGINT, STRING>. |
Le tableau suivant décrit les correspondances entre les types de données pris en charge dans MaxCompute SQL et les types de données Python 2. Vous devez écrire les UDF Python en vous basant sur ces correspondances afin de garantir la cohérence des types de données.
|
Type MaxCompute SQL |
Type Python 3 |
|
BIGINT |
INT |
|
STRING |
UNICODE |
|
DOUBLE |
FLOAT |
|
BOOLEAN |
BOOL |
|
DATETIME |
DATETIME.DATETIME |
|
FLOAT |
FLOAT |
|
CHAR |
UNICODE |
|
VARCHAR |
UNICODE |
|
BINARY |
BYTES |
|
DATE |
DATETIME.DATE |
|
DECIMAL |
DECIMAL.DECIMAL |
|
ARRAY |
LIST |
|
MAP |
DICT |
|
STRUCT |
COLLECTIONS.NAMEDTUPLE |
Référencement de ressources
Vous pouvez référencer des fichiers ou des tables dans le code UDF Python 2 en utilisant le module odps.distcache.
-
odps.distcache.get_cache_file(resource_name, mode): renvoie le contenu d'une ressource de fichier spécifiée selon lemodeindiqué.resource_nameest une chaîne de caractères qui spécifie le nom d'une table existante dans votre projet MaxCompute. Si le nom de la table n'est pas valide ou si la table n'existe pas, une erreur est renvoyée.Le paramètre
modeest de type STRING. La valeur par défaut est't'. Si vous définissezmodesur't', le fichier est ouvert en mode texte. Si vous définissezmodesur'b', le fichier est ouvert en mode binaire.La valeur de retour est un objet de type fichier. Lorsque cet objet n'est plus utilisé, vous devez appeler la méthode
closepour libérer le fichier ouvert.
Le code suivant illustre comment référencer un fichier.
from odps.udf import annotate from odps.distcache import get_cache_file @annotate('bigint->string') class DistCacheExample(object): def __init__(self): cache_file = get_cache_file('test_distcache.txt') kv = {} for line in cache_file: line = line.strip() if not line: continue k, v = line.split() kv[int(k)] = v cache_file.close() self.kv = kv def evaluate(self, arg): return self.kv.get(arg) -
odps.distcache.get_cache_table(resource_name): renvoie le contenu d'une ressource de table spécifiée.Le paramètre
resource_namespécifie une ressource de table existante dans le projet MaxCompute actuel. Une exception est levée si le nom de la ressource n'est pas valide ou si la ressource n'existe pas. Types de données pris en charge : BIGINT, STRING, DOUBLE, BOOLEAN, DATETIME, FLOAT, CHAR, VARCHAR, BINARY, DATE, DECIMAL, ARRAY, MAP et STRUCT.La valeur de retour est un générateur. Chaque itération produit un enregistrement de table sous forme de tableau.
Le code suivant illustre comment référencer une table.
from odps.udf import annotate
from odps.distcache import get_cache_table
@annotate('->string')
class DistCacheTableExample(object):
def __init__(self):
self.records = list(get_cache_table('udf_test'))
self.counter = 0
self.ln = len(self.records)
def evaluate(self):
if self.counter > self.ln - 1:
return None
ret = self.records[self.counter]
self.counter += 1
return str(ret)
Appel des UDF
Après avoir développé une UDF Python 3 en suivant le flux de travail de développement, vous pouvez l'appeler dans MaxCompute SQL comme suit :
Activation de Python 3
Par défaut, MaxCompute utilise Python 2. Pour utiliser Python 3, incluez l'indicateur de session suivant dans votre instruction SQL.
set odps.sql.python.version=cp37;
Appel de la fonction
Utilisation d'une UDF dans un projet MaxCompute : la méthode est similaire à celle des fonctions intégrées. Vous pouvez utiliser une fonction définie par l'utilisateur de la même manière qu'une fonction intégrée.
Utilisation d'une UDF entre projets : utilisez une UDF du projet B dans le projet A. L'instruction suivante montre un exemple :
select B:udf_in_other_project(arg0, arg1) as res from table_t;. Pour plus d'informations sur le partage interprojets, consultez la rubrique Accès aux ressources interprojets basé sur les packages.
Migration des UDF Python 2
Python 2 a atteint sa fin de vie (EOL) début 2020. Nous vous recommandons de migrer vos projets selon leur type :
Nouveaux projets : Pour les nouveaux projets MaxCompute ou les projets pour lesquels vous écrivez des UDF Python pour la première fois, utilisez Python 3 pour toutes les UDF Python.
-
Projets existants : Pour les projets comportant de nombreuses UDF Python 2, faites preuve de prudence lors de l'activation de Python 3. Pour effectuer une migration progressive, utilisez les méthodes suivantes :
Nouvelles tâches et nouvelles UDF : Utilisez Python 3 pour écrire les UDF et activez Python 3 au niveau de la session. Pour plus d'informations sur l'activation de Python 3, consultez la section Activer Python 3.
-
UDF Python 2 : Réécrivez les UDF Python 2 afin qu'elles soient compatibles avec Python 2 et Python 3. Pour plus d'informations sur la réécriture des UDF, consultez la page Porting Python 2 Code to Python 3.
RemarqueSi vous écrivez des UDF publiques partagées entre plusieurs projets MaxCompute, assurez-vous qu'elles sont compatibles avec Python 2 et Python 3.