O MaxCompute permite desenvolver funções definidas pelo usuário (UDFs) em Python 3 para implementar lógica de negócios personalizada.
Estrutura do código da UDF
Use o MaxCompute Studio para escrever uma UDF em Python 3. O código deve conter os seguintes componentes:
-
Importação de módulos: obrigatória.
O código da UDF deve incluir
from odps.udf import annotatepara importar a assinatura da função. Assim, o MaxCompute identifica a assinatura definida no código. Para referenciar arquivos ou tabelas no código da UDF, inclua tambémfrom odps.distcache import get_cache_fileoufrom odps.distcache import get_cache_table. -
Assinatura da função: obrigatória.
O formato é
@annotate(<signature>), em quesignaturedefine os tipos de dados dos parâmetros de entrada e do valor de retorno da função. Para mais informações sobre assinaturas de função, consulte Function signatures and data types. -
Classe Python personalizada: obrigatória.
A classe organiza o código da UDF 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 ou recursos de arquivo e tabela no código. Para mais detalhes, consulte Third-party library ou Reference resources.
-
Método
evaluate: obrigatório.O método evaluate está contido na classe Python personalizada. O método
evaluatedefine os parâmetros de entrada e o valor de retorno da UDF. Cada classe Python pode conter apenas um métodoevaluate.
O código a seguir apresenta um exemplo de 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
-
Acesso à Internet por meio de UDFs
Por padrão, o MaxCompute não permite acesso à Internet por meio de UDFs. Se for necessário acessar a Internet usando UDFs, preencha o formulário de solicitação de conexão de rede conforme suas necessidades de negócios e envie a solicitação. A equipe de suporte técnico do MaxCompute entrará em contato prontamente para ative a conectividade de rede. Para mais informações sobre como preencher o formulário de solicitação de conexão de rede, consulte Network connection process.
-
Acesso a uma VPC por meio de UDFs
Por padrão, o MaxCompute não permite o acesso a recursos em VPCs usando UDFs. Para usar UDFs no acesso a recursos dentro de uma VPC, estabeleça uma conexão de rede entre o MaxCompute e a VPC. Para mais informações sobre as operações relacionadas, consulte Access VPC resources from a UDF.
-
Leitura de dados de tabela via UDFs, UDAFs ou UDTFs
Não é possível usar UDFs, UDAFs ou UDTFs para ler dados dos seguintes tipos de tabela:
Tabela com evolução de schema aplicada
Tabela com tipos de dados complexos
Tabela com tipos de dados JSON
Tabela transacional
Observações de uso
O Python 3 não é compatível com o Python 2, e ambos não podem ser usados na mesma instrução SQL. Considere a compatibilidade antes de migrar.
O Python 2 atingiu o fim de vida útil (EOL) no início de 2020. Recomendamos migrar seus projetos com base no tipo de cada um.
Desenvolvimento de UDF: fluxo de trabalho geral
O desenvolvimento de UDF envolve preparar o ambiente, escrever o código, fazer upload e registrar a UDF e, em seguida, chamá-la. As seções a seguir detalham esse fluxo de trabalho com MaxCompute Studio, DataWorks e odpscmd.
MaxCompute Studio
-
Pré-requisitos
Instale o MaxCompute Studio e conecte-o a um projeto do MaxCompute antes de começar. Para mais informações, consulte os seguintes tópicos:
-
Escreva o código da UDF.
No painel Project, sob o diretório MaxCompute Studio, clique com o botão direito em scripts e selecione .
Na caixa de diálogo Create new MaxCompute python class, insira um nome de classe em Name, selecione Python UDF como tipo e clique em OK.
-
Escreva o código da UDF no editor.
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"NotaPara obter informações sobre como depurar UDFs Python localmente, consulte Test a UDF.
-
Faça upload e registre a UDF.
Clique com o botão direito no programa Python desejado e selecione Deploy to server…. Configure o nome da função e clique em OK. Para mais informações, consulte Upload a file and register a function.
Neste exemplo, o nome da função é definido como UDF_GET_URL_CHAR.
-
Chame a UDF.
No painel de navegação à esquerda, clique em Project Explore. Clique com o botão direito no projeto MaxCompute desejado, selecione Open Console e, em seguida, insira e execute a instrução SQL para chamar a 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);O resultado retornado é:
+-----+ | _c0 | +-----+ | a | +-----+
DataWorks
-
Pré-requisitos
Ative o DataWorks e associe-o a um projeto do MaxCompute antes de começar. Para mais informações, consulte Connect to MaxCompute by using DataWorks.
-
Escreva o código da UDF.
Desenvolva o código da UDF em qualquer ferramenta de desenvolvimento Python e empacote-o. O código a seguir serve como exemplo.
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" -
Faça upload e registre a UDF.
Carregue o código empacotado e registre a UDF no DataWorks. Para mais informações, consulte os seguintes tópicos:
-
Chame a UDF.
Após registrar a UDF, crie um nó ODPS SQL para escrever e executar instruções SQL que chamem a UDF. Para mais informações sobre nós ODPS SQL, consulte Develop an ODPS SQL task. O código a seguir fornece um exemplo da instrução 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é-requisitos
Baixe e instale o odpscmd e configure o arquivo config para conectar-se a um projeto do MaxCompute. Para mais informações, consulte Connect by using the MaxCompute client (odpscmd).
-
Escreva o código da UDF.
Desenvolva o código da UDF em qualquer ferramenta de desenvolvimento Python e empacote-o. O código a seguir serve como exemplo.
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" -
Faça upload e registre a UDF.
Carregue o código empacotado e registre a UDF usando o odpscmd. Para mais informações, consulte os seguintes tópicos:
-
Chame a UDF.
Após registrar a UDF, escreva e execute uma instrução SQL para chamá-la.
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);
Instalar a biblioteca NumPy
O ambiente de execução integrado do Python 3 não inclui o NumPy. Se sua UDF exigir NumPy, faça upload manual do pacote WHEEL. Ao baixar o pacote do PyPI ou de um site espelho, o nome do arquivo terá o formato numpy-<version>-cp37-cp37m-manylinux1_x86_64.whl. Para mais informações sobre como fazer upload de um pacote, consulte Resource operations ou Use a third-party package in a Python UDF.
Para obter uma lista das bibliotecas padrão suportadas pelo Python 3, consulte Biblioteca padrão do Python 3.
Assinaturas de função e tipos de dados
Formato das assinaturas de função:
@annotate(<signature>)
O parâmetro signature é uma string que especifica os tipos de dados dos parâmetros de entrada e do valor de retorno. Ao executar uma UDF, os tipos de dados dos parâmetros de entrada e do valor de retorno devem corresponder aos tipos especificados na assinatura da função. A consistência dos tipos de dados é verificada durante a análise semântica. Se houver inconsistência, um erro será retornado. Formato de uma assinatura:
'arg_type_list -> type'
Descrição dos parâmetros:
-
arg_type_list: especifica os tipos de dados dos parâmetros de entrada. Se houver múltiplos parâmetros de entrada, seus tipos de dados são separados por vírgulas (,). Os seguintes tipos de dados são suportados: BIGINT, STRING, DOUBLE, BOOLEAN, DATETIME, DECIMAL, FLOAT, BINARY, DATE, DECIMAL(precision,scale), CHAR e VARCHAR. Tipos de dados complexos, como ARRAY, MAP e STRUCT, bem como tipos complexos aninhados, também são suportados.arg_type_listpode ser representado por um asterisco (*) ou deixado vazio ('').Se
arg_type_listfor representado por um asterisco (*), um número variável de parâmetros de entrada será permitido.Se
arg_type_listfor deixado vazio (''), nenhum parâmetro de entrada será utilizado.
type: especifica o tipo de dados do valor de retorno. Uma UDF retorna apenas uma coluna de valores. Os seguintes tipos de dados são suportados: BIGINT, STRING, DOUBLE, BOOLEAN, DATETIME, DECIMAL, FLOAT, BINARY, DATE e DECIMAL(precision,scale). Tipos de dados complexos, como ARRAY, MAP e STRUCT, além de tipos complexos aninhados, também são suportados.
Ao escrever o código da UDF, selecione um tipo de dados com base na edição de tipos de dados do MaxCompute utilizada pelo seu projeto. Para mais informações sobre as edições de tipos de dados do MaxCompute e os tipos suportados em cada edição, consulte Data type editions.
A tabela a seguir fornece exemplos de assinaturas de função válidas.
|
Assinatura da função |
Descrição |
|
|
Os tipos de dados dos parâmetros de entrada são BIGINT e DOUBLE, e o tipo de dados do valor de retorno é STRING. |
|
|
Um número variável de parâmetros de entrada é utilizado e o tipo de dados do valor de retorno é STRING. |
|
|
Nenhum parâmetro de entrada é utilizado e o tipo de dados do valor de retorno é DOUBLE. |
|
|
O tipo de dados dos parâmetros de entrada é ARRAY<BIGINT> e o tipo de dados do valor de retorno é STRUCT<x:STRING, y:INT>. |
|
|
Nenhum parâmetro de entrada é utilizado e o tipo de dados do valor de retorno é MAP<BIGINT, STRING>. |
A tabela a seguir descreve os mapeamentos entre os tipos de dados suportados no MaxCompute SQL e os tipos de dados do Python 2. Escreva as UDFs Python com base nesses mapeamentos para garantir a consistência dos tipos de dados.
|
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
É possível referenciar arquivos ou tabelas no código de UDF Python 2 usando o módulo odps.distcache.
-
odps.distcache.get_cache_file(resource_name, mode): Retorna o conteúdo de um recurso de arquivo especificado nomodeindicado.resource_nameé uma string que especifica o nome de uma tabela existente no seu projeto MaxCompute. Se o nome da tabela for inválido ou se a tabela não existir, um erro será retornado.O parâmetro
modeé uma STRING. O valor padrão é't'. Se você definirmodecomo't', o arquivo será aberto em modo texto. Se definirmodecomo'b', o arquivo será aberto em modo binário.O valor de retorno é um objeto semelhante a um arquivo. Se esse objeto não for mais utilizado, chame o método
closepara liberar o arquivo aberto.
O código a seguir mostra como referenciar um arquivo.
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): Retorna o conteúdo de um recurso de tabela especificado.O parâmetro
resource_nameespecifica um recurso de tabela existente no projeto MaxCompute atual. Uma exceção será lançada se o nome do recurso for inválido ou se o recurso não existir. Tipos de dados suportados: BIGINT, STRING, DOUBLE, BOOLEAN, DATETIME, FLOAT, CHAR, VARCHAR, BINARY, DATE, DECIMAL, ARRAY, MAP e STRUCT.O valor de retorno é um Generator. Cada iteração produz um registro da tabela na forma de array.
O código a seguir mostra como referenciar uma tabela.
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)
Chamar UDFs
Após desenvolver uma UDF Python 3 seguindo o development workflow, chame-a no MaxCompute SQL da seguinte maneira:
Habilitar Python 3
Por padrão, o MaxCompute usa Python 2. Para usar Python 3, inclua a seguinte flag de sessão na sua instrução SQL.
set odps.sql.python.version=cp37;
Chamar a função
Usar uma UDF em um projeto MaxCompute: O método é semelhante ao uso de built-in functions. Utilize uma função definida pelo usuário da mesma forma que uma função integrada.
Usar uma UDF entre projetos: Use uma UDF do Projeto B no Projeto A. A instrução a seguir mostra um exemplo:
select B:udf_in_other_project(arg0, arg1) as res from table_t;. Para mais informações sobre compartilhamento entre projetos, consulte Cross-project resource access based on packages.
Migrar UDFs Python 2
O Python 2 atingiu seu EOL no início de 2020. Recomendamos migrar seus projetos com base no tipo:
Novos projetos: Para novos projetos MaxCompute ou projetos onde você está escrevendo UDFs Python pela primeira vez, utilize Python 3 para todas as UDFs Python.
-
Projetos existentes: Para projetos com muitas UDFs Python 2, tenha cautela ao habilitar o Python 3. Para migrar gradualmente, utilize os seguintes métodos:
Novos jobs e novas UDFs: Use Python 3 para escrever UDFs e habilite o Python 3 no nível da sessão. Para mais informações sobre como habilitar o Python 3, consulte Enable Python 3.
-
UDFs Python 2: Reescreva as UDFs Python 2 para torná-las compatíveis tanto com Python 2 quanto com Python 3. Para mais informações sobre como reescrever as UDFs, consulte Portando Código Python 2 para Python 3.
NotaSe você escrever UDFs públicas compartilhadas entre vários projetos MaxCompute, garanta que elas sejam compatíveis tanto com Python 2 quanto com Python 3.