Todos os produtos
Search
Central de documentação

MaxCompute:SELECT TRANSFORM

Última atualização: Aug 24, 2026

A instrução SELECT TRANSFORM inicia um processo filho específico e utiliza a entrada padrão para inserir dados no formato necessário. Em seguida, é possível analisar a saída padrão desse processo filho para obter os dados de resultado. A instrução SELECT TRANSFORM permite executar scripts em outras linguagens de programação sem precisar escrever funções com valor de tabela definidas pelo usuário (UDTFs).

Descrição

O desempenho do SELECT TRANSFORM e das UDTFs varia conforme o cenário. Testes comparativos indicam que o SELECT TRANSFORM apresenta melhor desempenho na consulta de pequenos volumes de dados. Por outro lado, as UDTFs superam o SELECT TRANSFORM em consultas de grandes volumes de dados. O SELECT TRANSFORM oferece desenvolvimento simplificado e é mais adequado para consultas ad hoc.

O SELECT TRANSFORM é compatível com diversas linguagens de programação. Essa instrução permite escrever scripts diretamente nos comandos para implementar funcionalidades simples. Linguagens como AWK, Python, Perl e Shell suportam essa operação. Assim, não é necessário executar etapas adicionais, como criar arquivos de script e fazer upload de resources, o que simplifica o processo de desenvolvimento. Para implementar funcionalidades complexas, faça o upload dos arquivos de script. Para mais informações, consulte {{XREF_0}} e {{XREF_1}}.

A tabela a seguir apresenta os resultados da comparação entre UDTFs e SELECT TRANSFORM em diferentes dimensões.

Categoria

select transform

UDTF

Tipo de dados

Um processo filho usa entrada e saída padrão para transmitir dados. Todos os dados são processados como strings. Ao usar o SELECT TRANSFORM, é necessária a conversão de tipo de dados.

Os resultados de saída e os parâmetros de entrada das UDTFs suportam múltiplos tipos de dados.

Transmissão de dados

A transmissão baseia-se no pipeline do sistema operacional. No entanto, o tamanho do cache do pipeline é de apenas 4 KB e não pode ser alterado. Se o pipeline estiver vazio ou totalmente ocupado, o SELECT TRANSFORM não será executado.

O SELECT TRANSFORM chama sistemas subjacentes para ler e gravar dados durante a transmissão. Essa instrução oferece desempenho superior na transmissão de dados em comparação com programas Java.

Não há limite imposto ao cache do pipeline.

Transmissão de parâmetros constantes

É necessária a transmissão de parâmetros constantes.

A transmissão de parâmetros constantes é opcional.

Processo

O SELECT TRANSFORM suporta processos pai e filho. Quando o uso de recursos computacionais é alto e o throughput de dados é baixo, o SELECT TRANSFORM aproveita o recurso multicore dos servidores.

Utiliza um único processo.

Desempenho

O SELECT TRANSFORM suporta código nativo de ferramentas como AWK. Isso permite que o SELECT TRANSFORM entregue desempenho superior ao de programas Java.

O desempenho é inferior.

Limites

PHP e Ruby não estão implantados nos clusters de computação do MaxCompute. Portanto, não é possível chamar scripts PHP ou Ruby no MaxCompute.

Sintaxe

select transform(<arg1>, <arg2> ...) 
[(row format delimited (fields terminated by <field_delimiter> (escaped by <character_escape>)) (null defined as <null_value>))]
using '<unix_command_line>' 
(resources '<res_name>' (',' '<res_name>')*)
[(as <col1>, <col2> ...)]
(row format delimited (fields terminated by <field_delimiter> (escaped by <character_escape>)) (null defined as <null_value>))
  • SELECT TRANSFORM palavra-chave: obrigatória. É possível substituir essa palavra-chave por map ou reduce, que possuem a mesma semântica. Para maior clareza sintática, recomenda-se o uso de SELECT TRANSFORM.

  • arg1,arg2...: obrigatório. Esses parâmetros especificam os dados de entrada. Seus formatos seguem o mesmo padrão das instruções SELECT. Caso utilize os formatos padrão, os resultados das expressões de cada parâmetro são convertidos implicitamente para valores do tipo STRING. Depois, os parâmetros são combinados com \t e passados ao processo filho especificado.

  • ROW FORMAT cláusula: opcional. Permite personalizar o formato dos dados de entrada e saída.

    A sintaxe utiliza duas cláusulas ROW FORMAT. A primeira define o formato dos dados de entrada, enquanto a segunda define o formato dos dados de saída. Por padrão, \t atua como delimitador de coluna, \n como delimitador de linha e \N representa valores nulos.

    Nota
    • Apenas um caractere pode ser usado como field_delimiter ou character_escape. Se uma string for especificada para esses parâmetros, somente o primeiro caractere será considerado.

    • O MaxCompute suporta sintaxes nos formatos definidos pelo Apache Hive, como inputRecordReader, outputRecordReader e SerDe. Para utilizar essas sintaxes, ative a edição de tipos de dados compatível com Hive. Adicione set odps.sql.hive.compatible=true; antes das instruções SQL. Para mais detalhes sobre as sintaxes suportadas pelo Apache Hive, consulte a documentação do Hive.

    • Ao especificar uma sintaxe suportada pelo Apache Hive, como inputRecordReader ou outputRecordReader, a execução das instruções SQL pode ficar mais lenta.

  • USING cláusula: obrigatória. Define o comando utilizado para iniciar o processo filho.

    • Na maioria das instruções SQL do MaxCompute, a cláusula USING especifica resources. Contudo, na instrução SELECT TRANSFORM, a cláusula USING define o comando para iniciar um processo filho. O uso da cláusula USING visa garantir a compatibilidade com a sintaxe do Apache Hive.

    • A sintaxe da cláusula USING assemelha-se à de um script shell. Entretanto, em vez de executar um script shell, a cláusula USING cria um processo filho com base no comando especificado. Logo, alguns recursos de shell, como redirecionamento de entrada e saída, pipeline e loops, não estão disponíveis. Se necessário, utilize um script shell como comando para iniciar o processo filho.

  • RESOURCES cláusula: opcional. Indica os resources acessíveis ao processo filho. Utilize um dos métodos abaixo para definir esses resources:

    • Utilize a cláusula RESOURCES para especificar os resources, por exemplo: using 'sh foo.sh bar.txt' resources 'foo.sh','bar.txt'.

    • Use set odps.sql.session.resources para definir os resources. Por exemplo, adicione a flag set odps.sql.session.resources=foo.sh,bar.txt; antes das instruções SQL.

      Após a aplicação dessa configuração global, todas as instruções SELECT TRANSFORM poderão acessar os resources. Separe múltiplos arquivos de resource com vírgulas (,).

  • AS cláusula: opcional. Especifica as colunas de saída e seus respectivos tipos de dados, como em as(col1 bigint, col2 boolean).

    • Caso os tipos de dados das colunas de saída não sejam definidos, o tipo padrão STRING será aplicado. Por exemplo, AS(col1, col2) indica que as colunas de saída são do tipo STRING.

    • Os dados de saída resultam da análise da saída padrão do processo filho. Se os dados especificados não forem do tipo STRING, o MaxCompute chama implicitamente a função CAST para converter o tipo de dados para STRING. Uma exceção de tempo de execução pode ocorrer durante essa conversão.

    • Não é permitido especificar tipos de dados apenas para algumas das colunas definidas, como em as(col1, col2:bigint).

    • Se a cláusula AS for omitida, o campo anterior ao primeiro \t nos dados de saída padrão será a chave, e todas as partes subsequentes serão o valor. Isso equivale a AS(key, value).

Exemplo de chamada de comandos shell

Execute um comando shell para gerar 50 linhas de dados, variando de 1 a 50. A saída corresponde ao campo data. Utilize a saída do comando shell como entrada para o SELECT TRANSFORM. Instrução de exemplo:

select transform(script) using 'sh' as (data) 
from (
        select  'for i in `seq 1 50`; do echo $i; done' as script
      ) t
;
-- The preceding statement is equivalent to the following statement: 
select transform('for i in `seq 1 50`; do echo $i; done') using 'sh' as (data);

O seguinte resultado é retornado:

+------------+
| data       |
+------------+
| 1          |
| 2          |
| 3          |
| 4          |
| 5          |
| 6          |
| 7          |
| 8          |
| 9          |
| 10         |
| 11         |
| 12         |
| 13         |
| 14         |
| 15         |
| 16         |
| 17         |
| 18         |
| 19         |
| 20         |
| 21         |
| 22         |
| 23         |
| 24         |
| 25         |
| 26         |
| 27         |
| 28         |
| 29         |
| 30         |
| 31         |
| 32         |
| 33         |
| 34         |
| 35         |
| 36         |
| 37         |
| 38         |
| 39         |
| 40         |
| 41         |
| 42         |
| 43         |
| 44         |
| 45         |
| 46         |
| 47         |
| 48         |
| 49         |
| 50         |
+------------+

Exemplo de chamada de comandos Python

Utilize um comando Python para gerar 50 linhas de dados, variando de 1 a 50. A saída corresponde ao campo data. Utilize a saída do comando Python como entrada para o SELECT TRANSFORM. Instrução de exemplo:

select transform(script) using 'python' as (data) 
from (
        select  'for i in xrange(1, 51):  print(i);' as script
      ) t
;
-- The preceding statement is equivalent to the following statement: 
select transform('for i in xrange(1, 51):  print(i);') using 'python' as (data);

O seguinte resultado é retornado:

+------------+
| data       |
+------------+
| 1          |
| 2          |
| 3          |
| 4          |
| 5          |
| 6          |
| 7          |
| 8          |
| 9          |
| 10         |
| 11         |
| 12         |
| 13         |
| 14         |
| 15         |
| 16         |
| 17         |
| 18         |
| 19         |
| 20         |
| 21         |
| 22         |
| 23         |
| 24         |
| 25         |
| 26         |
| 27         |
| 28         |
| 29         |
| 30         |
| 31         |
| 32         |
| 33         |
| 34         |
| 35         |
| 36         |
| 37         |
| 38         |
| 39         |
| 40         |
| 41         |
| 42         |
| 43         |
| 44         |
| 45         |
| 46         |
| 47         |
| 48         |
| 49         |
| 50         |
+------------+

Exemplo de chamada de comandos AWK

Crie uma tabela de teste. Execute um comando AWK para fornecer a segunda coluna da tabela de teste como saída. Os dados de saída correspondem ao campo data. Utilize a saída do comando AWK como entrada para o SELECT TRANSFORM. Instrução de exemplo:

-- Create a test table. 
create table testdata(c1 bigint,c2 bigint);
-- Insert test data into the test table.  
insert into table testdata values (1,4),(2,5),(3,6); 
-- Execute the SELECT TRANSFORM statement.  
select transform(*) using "awk '//{print $2}'" as (data) from testdata;

O seguinte resultado é retornado:

+------------+
| data       |
+------------+
| 4          |
| 5          |
| 6          |
+------------+

Exemplo de chamada de comandos Perl

Crie uma tabela de teste. Execute um comando Perl para fornecer os dados da tabela de teste como saída. Os dados de saída correspondem ao campo data. Utilize a saída do comando Perl como entrada para o SELECT TRANSFORM. Instrução de exemplo:

-- Create a test table. 
create table testdata(c1 bigint,c2 bigint);
-- Insert test data into the test table.  
insert into table testdata values (1,4),(2,5),(3,6); 
-- Execute the SELECT TRANSFORM statement.  
select transform(testdata.c1, testdata.c2) using "perl -e 'while($input = <STDIN>){print $input;}'" from testdata;

O seguinte resultado é retornado:

+------------+------------+
| key        | value      |
+------------+------------+
| 1          | 4          |
| 2          | 5          |
| 3          | 6          |
+------------+------------+

Exemplo de chamada de scripts Python

  1. Crie o arquivo myplus.py. Instruções de exemplo:

    #!/usr/bin/env python
    import sys
    line = sys.stdin.readline()
    while line:
        token = line.split('\t')
        if (token[0] == '\\N') or (token[1] == '\\N'):
            print('\\N')
        else:
            print(str(token[0]) +'\t' + str(token[1]))
        line = sys.stdin.readline()
  2. Adicione o arquivo de script Python como um resource no MaxCompute.

    add py ./myplus.py -f;
    Nota

    Também é possível utilizar o console do DataWorks para adicionar o arquivo Python como resource. Para mais informações, consulte {{XREF_2}}.

  3. Execute a instrução SELECT TRANSFORM para chamar esse arquivo.

    -- Create a test table. 
    create table testdata(c1 bigint,c2 bigint);
    -- Insert test data into the test table.  
    insert into table testdata values (1,4),(2,5),(3,6); 
    -- Execute the SELECT TRANSFORM statement.  
    select 
    transform (testdata.c1, testdata.c2) 
    using 'python myplus.py' resources 'myplus.py' 
    as (result1,result2) 
    from testdata;
    -- The preceding statements are equivalent to the following statements: 
    set odps.sql.session.resources=myplus.py;
    select transform (testdata.c1, testdata.c2) 
    using 'python myplus.py' 
    as (result1,result2) 
    from testdata;

    O seguinte resultado é retornado:

    +------------+------------+
    | result1    | result2    |
    +------------+------------+
    | 1          | 4          |
    |            | NULL       |
    | 2          | 5          |
    |            | NULL       |
    | 3          | 6          |
    |            | NULL       |
    +------------+------------+

Exemplo de chamada de scripts Java

  1. Escreva um script Java e exporte-o como o arquivo Sum.jar. Código Java de exemplo:

    package com.aliyun.odps.test;
    import java.util.Scanner;
    public class Sum {
        public static void main(String[] args) {
            Scanner sc = new Scanner(System.in);
            while (sc.hasNext()) {
                String s = sc.nextLine();
                String[] tokens = s.split("\t");
                if (tokens.length < 2) {
                    throw new RuntimeException("illegal input");
                }
                if (tokens[0].equals("\\N") || tokens[1].equals("\\N")) {
                    System.out.println("\\N");
                }
                System.out.println(Long.parseLong(tokens[0]) + Long.parseLong(tokens[1]));
            }
        }
    }
  2. Adicione o arquivo como um resource no MaxCompute.

    add jar ./Sum.jar -f;
  3. Execute a instrução SELECT TRANSFORM para chamar esse arquivo.

    -- Create a test table. 
    create table testdata(c1 bigint,c2 bigint); 
    -- Insert test data into the test table. 
    insert into table testdata values (1,4),(2,5),(3,6); 
    -- Execute the SELECT TRANSFORM statement. 
    select transform(testdata.c1, testdata.c2) using 'java -cp Sum.jar com.aliyun.odps.test.Sum' resources 'Sum.jar' as cnt from testdata;
    -- The preceding statements are equivalent to the following statements: 
    set odps.sql.session.resources=Sum.jar; 
    select transform(testdata.c1, testdata.c2) using 'java -cp Sum.jar com.aliyun.odps.test.Sum' as cnt from testdata;

    O seguinte resultado é retornado:

    +-----+
    | cnt |
    +-----+
    | 5   |
    | 7   |
    | 9   |
    +-----+
Nota

Java e Python possuem frameworks UDTF prontos para uso. No entanto, o SELECT TRANSFORM facilita a escrita de scripts. O SELECT TRANSFORM não exige dependências adicionais nem impõe requisitos de formato, permitindo inclusive o uso direto de scripts offline. O diretório para salvar scripts Java offline pode ser obtido pela variável de ambiente JAVA_HOME. Já o diretório para salvar scripts Python offline pode ser obtido pela variável de ambiente PYTHON_HOME.

Exemplo de chamada de scripts em série

É possível executar instruções SELECT TRANSFORM em série. Para realizar essa operação, utilize as cláusulas DISTRIBUTE BY e SORT BY para pré-processar os dados de entrada. Instrução de exemplo:

select transform(key, value) using '<cmd2>' from 
(
    select transform(*) using '<cmd1>' from 
    (
        select * from testdata distribute by c2 sort by c1 
    ) t distribute by key sort by value 
) t2;

cmd1 e cmd2 são os comandos utilizados para iniciar os processos filhos.

Também é possível utilizar as palavras-chave map e reduce para executar instruções SELECT TRANSFORM em série.

@a := select * from data distribute by col2 sort by col1;
@b := map * using 'cmd1' distribute by col1 sort by col2 from @a;
reduce * using 'cmd2' from @b;