Todos os produtos
Search
Central de documentação

MaxCompute:UDAF em Python 3

Última atualização: Aug 21, 2026

A Python Software Foundation encerrará em breve a manutenção do Python 2. O MaxCompute agora oferece suporte ao Python 3, especificamente à versão CPython-3.7.3. Este tópico descreve como escrever uma função de agregação definida pelo usuário (UDAF) em Python 3.

Estrutura do código da UDAF

Use o MaxCompute Studio para escrever o código de uma função de agregação definida pelo usuário (UDAF) em Python 3. O código deve conter os seguintes elementos:

  • Importação de módulos: Obrigatório.

    Importe pelo menos from odps.udf import annotate e from odps.udf import BaseUDAF. A instrução from odps.udf import annotate importa o módulo de assinatura da função, permitindo que o MaxCompute reconheça a assinatura definida no código. A instrução from odps.udf import BaseUDAF importa a classe base para UDAFs em Python. Implemente métodos como iterate, merge e terminate na classe derivada.

    Se o código da UDAF precisar referenciar recursos de arquivo ou tabela, inclua from odps.distcache import get_cache_file para recursos de arquivo ou from odps.distcache import get_cache_table para recursos de tabela.

  • Assinatura da função: Obrigatório.

    O formato é @annotate(<signature>). O parâmetro signature define os tipos de dados dos parâmetros de entrada e do valor de retorno da função. Para obter mais informações sobre assinaturas de função, consulte Function signature and data types.

  • Classe Python personalizada (classe derivada): Obrigatório.

    Esta classe atua como unidade organizacional do código da UDAF e define as variáveis e os métodos que implementam a lógica de negócios. Também é possível referenciar bibliotecas de terceiros integradas, arquivos ou recursos de tabela no código. Para mais detalhes, consulte Third-party libraries ou Reference resources.

  • Implementação dos métodos da classe Python: Obrigatório.

    A implementação da classe Python inclui os métodos listados abaixo. Implemente-os conforme a necessidade.

    Definição do método

    Descrição

    BaseUDAF.new_buffer()

    Retorna um buffer para o valor intermediário da função de agregação. O buffer deve ser um objeto Marshal, como LIST ou DICT. O tamanho do buffer não deve aumentar proporcionalmente ao volume de dados. Em casos extremos, o tamanho do buffer após a serialização do objeto não pode exceder 2 MB.

    BaseUDAF.iterate(buffer[, args, ...])

    Agrega os argumentos args ao valor intermediário armazenado em buffer.

    BaseUDAF.merge(buffer, pbuffer)

    Combina os valores intermediários buffer e pbuffer, armazenando o resultado em buffer.

    BaseUDAF.terminate(buffer)

    Converte o conteúdo de buffer em um tipo de dados primitivo do MaxCompute SQL.

O código a seguir apresenta um exemplo de UDAF.

# Import the function signature module and the base class.
from odps.udf import annotate
from odps.udf import BaseUDAF
# Function signature.
@annotate('double->double')
# Custom Python class.
class Average(BaseUDAF):
# Implement the methods of the Python class.
    def new_buffer(self):
        return [0, 0]
    def iterate(self, buffer, number):
        if number is not None:
            buffer[0] += number
            buffer[1] += 1
    def merge(self, buffer, pbuffer):
        buffer[0] += pbuffer[0]
        buffer[1] += pbuffer[1]
    def terminate(self, buffer):
        if buffer[1] == 0:
            return 0.0
        return buffer[0] / buffer[1]

A figura a seguir ilustra a lógica de implementação e o fluxo de cálculo de uma UDAF do MaxCompute para calcular o valor médio (

avg

).

求平均值逻辑

O parâmetro

pbuffer

corresponde a

pr

na figura, enquanto

buffer

corresponde a

r

.

Nota

A diferença entre UDAFs em Python 2 e Python 3 reside na versão subjacente do Python. Escreva sua UDAF com base nos recursos da versão correspondente.

Observações de uso

O Python 3 não é compatível com o Python 2, e ambas as versões não podem ser usadas na mesma instrução SQL. Avalie a compatibilidade antes de fazer a migração.

Nota

O Python 2 atingiu o fim da vida útil (EOL) no início de 2020. Recomendamos migrar seus projetos de acordo com o tipo de cada um.

Migração de UDAF em Python 2

Como a Python Software Foundation encerrará em breve a manutenção do Python 2, recomendamos migrar seus projetos conforme o tipo:

  • Novos projetos: Aplica-se a novos projetos do MaxCompute ou a projetos nos quais você está escrevendo uma UDAF em Python pela primeira vez. Recomendamos escrever todas as UDAFs em Python usando a versão 3.

  • Projetos existentes: Aplica-se a projetos do MaxCompute que já possuem muitas UDAFs em Python 2. Ative o Python 3 com cautela. Se planeja migrar gradualmente todas as UDAFs do Python 2 para o Python 3, utilize os métodos a seguir:

    • Novos jobs e novas UDAFs: Escreva-os em Python 3 e ative o Python 3 no nível da sessão. Para obter mais informações sobre como ativar o Python 3, consulte Enable Python 3.

    • UDAFs em Python 2: Reescreva o código das UDAFs existentes para garantir compatibilidade tanto com Python 2 quanto com Python 3. Para saber mais sobre como reescrever o código, consulte Porting Python 2 Code to Python 3.

      Nota

      Se você pretende criar uma UDAF pública e conceder permissões de uso para vários projetos do MaxCompute, recomendamos tornar a UDAF compatível com Python 2 e Python 3 simultaneamente.

Ativar o Python 3

Por padrão, o MaxCompute utiliza o Python 2. Para usar o Python 3, inclua o seguinte sinalizador de sessão na sua instrução SQL.

set odps.sql.python.version=cp37;

Bibliotecas de terceiros

O ambiente de execução integrado do Python 3 no MaxCompute não possui a biblioteca de terceiros NumPy instalada. Para utilizar uma UDAF que dependa do NumPy, faça o upload manual do pacote WHEEL do NumPy. Ao baixar o pacote NumPy do PyPI ou de um espelho, o nome do arquivo será numpy-<version_number>-cp37-cp37m-manylinux1_x86_64.whl. Para obter mais informações sobre como fazer upload de pacotes, consulte Resource operations ou UDF example: Use a third-party package in a Python UDF.

Assinatura da função e tipos de dados

A assinatura da função segue o formato abaixo.

@annotate(<signature>)

O parâmetro

signature

é uma string que identifica os tipos de dados dos parâmetros de entrada e do valor de retorno. Ao executar uma UDAF, os tipos de dados de entrada e saída devem corresponder exatamente aos tipos especificados na assinatura. Durante a fase de análise da consulta, o sistema valida a chamada da função comparando-a com a assinatura definida. Caso haja incompatibilidade de tipos, um erro será reportado. O formato específico é o seguinte:

'arg_type_list -> type'

onde:

  • arg_type_list: Representa os tipos de dados dos parâmetros de entrada. É possível especificar múltiplos parâmetros separados por vírgulas (,). Os tipos suportados incluem BIGINT, STRING, DOUBLE, BOOLEAN, DATETIME, DECIMAL, FLOAT, BINARY, DATE, DECIMAL(precision,scale), CHAR, VARCHAR, tipos complexos (ARRAY, MAP, STRUCT) e tipos complexos aninhados.

    O campo arg_type_list também aceita um asterisco (*) ou uma string vazia ('').

    • Quando arg_type_list for um asterisco (*), indica que a função aceita qualquer quantidade de parâmetros de entrada.

    • Quando arg_type_list for uma string vazia (''), indica que a função não possui parâmetros de entrada.

    Para mais detalhes sobre a sintaxe estendida da anotação Resolve, consulte Dynamic parameters for UDAFs and UDTFs.

  • type: Representa o tipo de dado do valor de retorno. Uma UDAF retorna apenas uma coluna. Os tipos suportados incluem BIGINT, STRING, DOUBLE, BOOLEAN, DATETIME, DECIMAL, FLOAT, BINARY, DATE, DECIMAL(precision,scale), tipos complexos (ARRAY, MAP, STRUCT) e tipos complexos aninhados.

Nota

Ao escrever o código da UDAF, selecione os tipos de dados apropriados com base na edição de tipos de dados do seu projeto MaxCompute. Para obter mais informações sobre as edições de tipos de dados e os tipos suportados em cada uma, consulte

Data type editions

.

Veja a seguir exemplos válidos de assinaturas de função.

Exemplo de assinatura de função

Descrição

@annotate('bigint,double->string')

Os tipos dos parâmetros de entrada são BIGINT e DOUBLE, e o tipo do valor de retorno é STRING.

@annotate('*->string')

A função aceita qualquer número de parâmetros de entrada, e o tipo do valor de retorno é STRING.

@annotate('->double')

A função não possui parâmetros de entrada, e o tipo do valor de retorno é DOUBLE.

@annotate('array<bigint>->struct<x:string, y:int>')

O tipo do parâmetro de entrada é ARRAY, e o tipo do valor de retorno é STRUCT.

Para garantir que os tipos de dados na sua UDAF em Python sejam consistentes com os tipos suportados pelo MaxCompute, utilize os mapeamentos corretos. A tabela a seguir descreve esses mapeamentos.

Tipo do MaxCompute SQL

Tipo do 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

Referenciar recursos

As UDAFs em Python podem referenciar recursos de arquivo e tabela utilizando o módulo odps.distcache.

  • odps.distcache.get_cache_file(resource_name): Retorna um objeto semelhante a um arquivo para o recurso de arquivo especificado.

    • O parâmetro resource_name é do tipo STRING e corresponde ao nome de um recurso de arquivo existente no projeto atual do MaxCompute. Se o nome do recurso for inválido ou se o recurso não existir, uma exceção será lançada.

      Nota

      Para acessar um recurso a partir de uma UDAF, declare o recurso referenciado durante a criação da UDAF. Caso contrário, um erro será reportado.

    • O valor retornado é um objeto semelhante a um arquivo. Após terminar de usar esse objeto, chame o método close para liberar o arquivo de recurso aberto.

  • odps.distcache.get_cache_table(resource_name): Retorna um objeto gerador para o recurso de tabela especificado.

    • O parâmetro resource_name é do tipo STRING e corresponde ao nome de um recurso de tabela existente no projeto atual do MaxCompute. Se o nome do recurso de tabela for inválido ou se o recurso não existir, uma exceção será lançada.

    • O valor retornado é do tipo GENERATOR. O chamador percorre o gerador para recuperar o conteúdo da tabela. Cada iteração retorna um registro da tabela na forma de um array.

Para obter mais informações sobre o uso, consulte Reference resources (Python 3 UDF) e Reference resources (Python 3 UDTF).

Observações de uso

Após desenvolver uma UDAF em Python 3 seguindo as instruções em development flow, chame-a em uma instrução SQL do MaxCompute. Os métodos de chamada são os seguintes:

  • Usar uma UDF dentro de um projeto do MaxCompute: O método é semelhante ao uso de built-in functions. Utilize a função definida pelo usuário da mesma forma que usaria uma função integrada.

  • Usar uma UDF entre projetos: Utilize uma UDF do Projeto B dentro do Projeto A. A instrução a seguir mostra um exemplo: select B:udf_in_other_project(arg0, arg1) as res from table_t;. Para obter mais informações sobre compartilhamento entre projetos, consulte Cross-project resource access based on packages.

Para obter o procedimento completo de desenvolvimento e chamada de uma UDAF em Python 3 usando o MaxCompute Studio, consulte Develop a Python UDF.

Parâmetros dinâmicos para UDAFs

Assinatura da função

Para obter mais informações sobre o formato da assinatura de função de uma UDAF em Python, consulte Function signature and data types.

  • Utilize um asterisco (*) na lista de parâmetros para aceitar parâmetros de entrada em qualquer quantidade e de qualquer tipo. Por exemplo, @annotate('double,*->string') indica que o primeiro parâmetro é do tipo DOUBLE, seguido por uma lista de parâmetros de qualquer quantidade e tipo. Nesse caso, escreva o código para determinar a quantidade e os tipos dos parâmetros de entrada e execute as operações correspondentes. Isso é semelhante à função printf na linguagem C.

    Nota

    Um asterisco (*) tem um significado diferente quando usado na lista de valores de retorno.

  • Utilize um asterisco (*) no valor de retorno de uma UDTF para indicar qualquer quantidade de valores de retorno do tipo STRING. A quantidade de valores retornados depende do número de aliases definidos no momento da chamada da função. Por exemplo, para @annotate("bigint,string->double,*"), o método de chamada é UDTF(x, y) as (a, b, c). Neste exemplo, três aliases são definidos após as: a, b e c. O editor considera a como sendo do tipo DOUBLE, pois o tipo da primeira coluna no valor de retorno foi especificado na anotação, e considera b e c como sendo do tipo STRING. Como três valores de retorno foram especificados, quando a UDTF chamar forward, o argumento de forward deve ser um array de comprimento 3. Caso contrário, ocorrerá um erro de tempo de execução.

    Nota

    Esse tipo de erro não pode ser detectado em tempo de compilação. Portanto, quem chama a UDTF deve definir a quantidade de aliases na instrução SQL seguindo as regras estabelecidas pela própria UDTF. Como a quantidade de valores de retorno de uma função de agregação é fixa em 1, esse recurso não se aplica a uma UDAF.

Exemplo de UDAF

from odps.udf import annotate
from odps.udf import BaseUDAF
@annotate('bigint,*->string')
class MultiColSum(BaseUDAF):
    def new_buffer(self):
        return [0]
    def iterate(self, buffer, *args):
        for arg in args:
            buffer[0] += int(arg)
    def merge(self, buffer, pbuffer):
        buffer[0] += pbuffer[0]
    def terminate(self, buffer):
        return str(buffer[0])

Uma UDAF pode ter apenas um valor de retorno. No exemplo anterior, o valor retornado é a soma de múltiplos parâmetros de entrada, que depois é agregada e somada em várias linhas. O código a seguir fornece um exemplo de uso.

-- Sums multiple input parameters.
SELECT my_multi_col_sum(a,b,c,d,e) from values (1,"2","3","4","5"), (6,"7","8","9","10") t(a,b,c,d,e);
-- The return value is 55.