La versión de Python 2 que utiliza MaxCompute es la 2.7. Este tema describe cómo escribir una función definida por el usuario (UDF) en Python 2.
Estructura del código de la UDF
Puede usar MaxCompute Studio para escribir código de UDF en Python 2. El código de la UDF puede contener la siguiente información:
-
Declaración de codificación: opcional.
El formato de la declaración es
#coding:utf-8o# -*- coding: utf-8 -*-. Ambos formatos son equivalentes. Si aparecen caracteres chinos en el código de la UDF escrito en Python 2, se devuelve un error al ejecutar la UDF. Para solucionar este problema, debe agregar una declaración de codificación al encabezado del código. -
Importación de módulos: obligatorio.
El código de la UDF debe incluir
from odps.udf import annotate, que se utiliza para importar la firma de la función. De esta manera, MaxCompute puede identificar la firma de la función definida en el código. Si desea hacer referencia a archivos o tablas en el código de la UDF, este debe incluirfrom odps.distcache import get_cache_fileofrom odps.distcache import get_cache_table. -
Firma de la función: obligatorio.
La firma de la función tiene el formato
@annotate(<signature>). El parámetrosignaturese usa para definir los tipos de datos de los parámetros de entrada y el valor de retorno de la UDF. Para obtener más información sobre las firmas de funciones, consulte Function signatures and data types. -
Clase de Python personalizada: obligatorio.
Una clase de Python personalizada es la unidad organizativa del código de la UDF. Esta clase define las variables y los métodos que se utilizan para cumplir con sus requisitos empresariales. En el código de la UDF, también puede hacer referencia a bibliotecas de terceros instaladas en MaxCompute, o bien a archivos o tablas. Para obtener más información, consulte Third-party libraries o Reference resources.
-
Método
evaluate: obligatorio.El método evaluate está contenido en la clase de Python personalizada. El método
evaluatedefine los parámetros de entrada y el valor de retorno de la UDF. Cada clase de Python solo puede contener un métodoevaluate.
Código de ejemplo:
#coding:utf-8
# Import the function signature.
from odps.udf import annotate
# The function signature.
@annotate("bigint,bigint->bigint")
# The custom Python class.
class MyPlus(object):
# The evaluate method.
def evaluate(self, arg0, arg1):
if None in (arg0, arg1):
return None
return arg0 + arg1
Límites
MaxCompute permite escribir UDF de Python 2 en Python 2.7 y ejecutar el código de la UDF en un entorno sandbox. En este entorno, están prohibidas las siguientes operaciones:
Leer datos de archivos locales y escribir datos en ellos.
Iniciar subprocesos.
Iniciar hilos.
Habilitar la comunicación por socket.
Usar otros sistemas para llamar a UDF de Python 2.
Debido a estos límites, el código que cargue debe escribirse mediante bibliotecas estándar de Python. Si hay módulos o módulos de extensión C en las bibliotecas estándar de Python involucrados en las operaciones anteriores, no se podrán utilizar. Tenga en cuenta los siguientes puntos sobre los módulos en las bibliotecas estándar de Python:
Todos los módulos implementados con base en bibliotecas estándar de Python y que no dependen de módulos de extensión están disponibles.
-
Los siguientes módulos de extensión C están disponibles:
array y audioop
binascii y bisect
cmath, _codecs_cn, _codecs_hk, _codecs_iso2022, _codecs_jp, _codecs_kr, _codecs_tw, _collections y cStringIO
datetime
_functools y future_builtins
_heapq y _hashlib
itertools
_json
_locale y _lsprof
math, _md5 y _multibytecodec
operator
_random
_sha256, _sha512, _sha, _struct y strop
time
unicodedata
_weakref
cPickle
Al ejecutar código de UDF en un entorno sandbox, el tamaño máximo de datos que se pueden escribir en la salida estándar (sys.stdout) o en la salida de error estándar (
sys.stderr) es de 20 KB. Si el tamaño supera los 20 KB, se ignoran los caracteres adicionales.
Bibliotecas de terceros
Las bibliotecas de terceros, como NumPy, están instaladas en el entorno de Python 2 de MaxCompute como complemento a las bibliotecas estándar.
El uso de bibliotecas de terceros está sujeto a ciertos límites. Por ejemplo, al utilizar una biblioteca de terceros, no se permite acceder a datos locales y solo se pueden usar recursos de E/S de red limitados. Las API relacionadas en las bibliotecas de terceros están deshabilitadas.
Firmas de funciones y tipos de datos
Formato de las firmas de funciones:
@annotate(<signature>)
El parámetro signature es una cadena que especifica los tipos de datos de los parámetros de entrada y del valor de retorno. Al ejecutar una UDF, los tipos de datos de los parámetros de entrada y del valor de retorno deben coincidir con los tipos de datos especificados en la firma de la función. La consistencia de los tipos de datos se comprueba durante el análisis sintáctico semántico. Si los tipos de datos no coinciden, se devuelve un error. Formato de una firma:
'arg_type_list -> type'
Descripción de parámetros:
-
arg_type_list: especifica los tipos de datos de los parámetros de entrada. Si se utilizan varios parámetros de entrada, sus tipos de datos se separan con comas (,). Se admiten los siguientes tipos de datos: BIGINT, STRING, DOUBLE, BOOLEAN, DATETIME, DECIMAL, FLOAT, BINARY, DATE, DECIMAL(precision,scale), CHAR y VARCHAR. También se admiten tipos de datos complejos, como ARRAY, MAP y STRUCT, así como tipos de datos complejos anidados.arg_type_listpuede representarse con un asterisco (*) o dejarse vacío ('').Si
arg_type_listse representa con un asterisco (*), se permite un número variable de parámetros de entrada.Si
arg_type_listse deja vacío (''), no se utilizan parámetros de entrada.
type: especifica el tipo de dato del valor de retorno. Para una UDF, solo se devuelve una columna de valores. Se admiten los siguientes tipos de datos: BIGINT, STRING, DOUBLE, BOOLEAN, DATETIME, DECIMAL, FLOAT, BINARY, DATE y DECIMAL(precision,scale). También se admiten tipos de datos complejos, como ARRAY, MAP y STRUCT, así como tipos de datos complejos anidados.
Al escribir código de UDF, puede seleccionar un tipo de dato según la edición de tipos de datos de MaxCompute que utilice su proyecto de MaxCompute. Para obtener más información sobre las ediciones de tipos de datos de MaxCompute y los tipos de datos compatibles en cada edición, consulte Data type editions.
A continuación se presentan ejemplos de firmas de funciones válidas.
|
Firma de la función |
Descripción |
|
|
Los tipos de datos de los parámetros de entrada son BIGINT y DOUBLE, y el tipo de dato del valor de retorno es STRING. |
|
|
Se utiliza un número variable de parámetros de entrada y el tipo de dato del valor de retorno es STRING. |
|
|
No se utilizan parámetros de entrada y el tipo de dato del valor de retorno es DOUBLE. |
|
|
El tipo de dato de los parámetros de entrada es ARRAY<BIGINT> y el tipo de dato del valor de retorno es STRUCT<x:STRING, y:INT>. |
|
|
No se utilizan parámetros de entrada y el tipo de dato del valor de retorno es MAP<BIGINT, STRING>. |
La siguiente tabla describe las asignaciones entre los tipos de datos compatibles con MaxCompute SQL y los tipos de datos de Python 2. Debe escribir las UDF de Python basándose en estas asignaciones para garantizar la consistencia de los tipos de datos.
|
Tipo de dato de MaxCompute SQL |
Tipo de dato de Python 2 |
|
BIGINT |
INT |
|
STRING |
STR |
|
DOUBLE |
FLOAT |
|
BOOLEAN |
BOOL |
|
DATETIME |
INT |
|
FLOAT |
FLOAT |
|
CHAR |
STR |
|
VARCHAR |
STR |
|
BINARY |
BYTEARRAY |
|
DATE |
INT |
|
DECIMAL |
DECIMAL.DECIMAL |
|
ARRAY |
LIST |
|
MAP |
DICT |
|
STRUCT |
COLLECTIONS.NAMEDTUPLE |
El tipo DATETIME compatible con MaxCompute SQL se asigna al tipo de dato INT de Python. Un valor de tipo INT sigue el formato UNIX, que corresponde al número de milisegundos transcurridos desde las 00:00:00 del jueves 1 de enero de 1970. Puede procesar datos de tipo DATETIME mediante el módulo DATETIME en las bibliotecas estándar de Python.
Se agregó el parámetro
silentaodps.udf.int(value). Si el parámetrosilentse establece en True y el tipo de dato devalueno se puede convertir al tipo INT, se devuelve None y no se genera ningún error.NULL en MaxCompute SQL se asigna a None en Python 2.
Referencia a recursos
Puede hacer referencia a archivos o tablas en el código de UDF de Python 2 mediante el módulo odps.distcache.
-
odps.distcache.get_cache_file(resource_name): devuelve el contenido de un archivo especificado.-
resource_namees una cadena que especifica el nombre de un archivo existente en su proyecto de MaxCompute. Si el nombre del archivo no es válido o el archivo no existe, se devuelve un error.NotaPara hacer referencia a un archivo en el código de la UDF, debe declarar el archivo al crear la UDF. De lo contrario, se devolverá un error al llamar a la UDF.
El valor de retorno es un objeto similar a un archivo. Si este objeto ya no se utiliza, debe llamar al método
closepara liberar el archivo abierto.
El siguiente código muestra cómo hacer referencia a un archivo.
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): devuelve el contenido de una tabla especificada.resource_namees una cadena que especifica el nombre de una tabla existente en su proyecto de MaxCompute. Si el nombre de la tabla no es válido o la tabla no existe, se devuelve un error.El valor de retorno es del tipo de datos GENERATOR. El llamante recorre la tabla para obtener su contenido. Se obtiene un registro de tipo ARRAY cada vez que el llamante recorre la tabla.
El siguiente código muestra cómo hacer referencia a una tabla.
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)
Proceso de desarrollo
Al desarrollar una UDF, debe realizar preparativos, escribir el código de la UDF, cargar el programa de Python, crear la UDF, depurarla y llamarla. MaxCompute permite utilizar diversas herramientas para desarrollar una UDF, como MaxCompute Studio, DataWorks y el cliente de MaxCompute (odpscmd).
El proceso para desarrollar UDF en Python 2 con diversas herramientas es el mismo que para desarrollar UDF en Python 3. Para obtener más información sobre el proceso de desarrollo y ejemplos de cómo desarrollar una UDF en Python, consulte Development process.
Para obtener más información sobre cómo usar MaxCompute Studio para desarrollar y llamar a una UDF en Python 2, consulte Develop a Python UDF.
Notas de uso
Después de desarrollar una UDF de Python 2, puede usar MaxCompute SQL para llamar a dicha UDF. Puede llamar a una UDF de Python 2 mediante uno de los siguientes métodos:
Uso de una UDF en un proyecto de MaxCompute: El método es similar al uso de built-in functions. Puede utilizar una función definida por el usuario de la misma manera que una función integrada.
Uso de una UDF entre proyectos: Uso de una UDF del Proyecto B en el Proyecto A. La siguiente sentencia muestra un ejemplo:
select B:udf_in_other_project(arg0, arg1) as res from table_t;. Para obtener más información sobre el uso compartido entre proyectos, consulte Cross-project resource access based on packages.