Todos os produtos
Search
Central de documentação

MaxCompute:Custom storage handler

Última atualização: Jun 27, 2026

Se seus dados no OSS utilizam um formato não suportado pelos handlers nativos do MaxCompute — como um formato binário proprietário, um delimitador personalizado ou uma codificação específica de domínio — o storage handler personalizado permite implementar a própria lógica de leitura e escrita. Desenvolva o handler como uma função definida pelo usuário (UDF) do MaxCompute em Java, empacote-o como um JAR e referencie-o durante a criação da tabela externa. O MaxCompute delega toda a leitura e escrita de dados ao seu handler.

Observações de uso

Restrição

Detalhe

Propriedade cluster

Não suportada em tabelas externas do OSS.

Tamanho de arquivo único

Não pode exceder 2 GB. Divida arquivos maiores que 2 GB antes de referenciá-los.

Sharding de dados

Desativado por padrão para evitar problemas de integridade. Ative essa opção apenas se o seu storage handler oferecer suporte explícito a sharding.

Para ativar o sharding e iniciar múltiplos mappers, execute:

SET odps.sql.unstructured.data.single.file.split.enabled=true;

Crie uma tabela externa

Sintaxe

CREATE EXTERNAL TABLE [IF NOT EXISTS] <table_name>
(
  col_name data_type,
  ...
)
[COMMENT table_comment]
[PARTITIONED BY (col_name data_type, ...)]
STORED BY '<storage_handler_class>'
WITH SERDEPROPERTIES (
  ['property_name'='property_value', ...]
)
LOCATION 'oss://<endpoint>/<bucket>/<path>/'
USING '<jar_name>';

Para parâmetros comuns, como definições de colunas e sintaxe de partição, consulte Parâmetros básicos de sintaxe.

Parâmetros

Parâmetro

Obrigatório

Descrição

storage_handler_class

Sim

Nome de classe totalmente qualificado do seu storage handler personalizado, implementado como uma UDF do MaxCompute. Consulte Desenvolver UDFs.

jar_name

Sim

Pacote JAR contendo o código do storage handler. Adicione o JAR como recurso ao seu projeto do MaxCompute antes de criar a tabela. Consulte Operações de recursos.

resource_name

Não

Pacotes JAR adicionais necessários quando o handler utiliza uma classe SerDe personalizada. Adicione cada JAR como um recurso separado ao projeto do MaxCompute. Consulte Operações de recursos.

Escrever dados

Para a sintaxe de escrita de dados, consulte Escrever dados no OSS.

Consulta e análise

Para a sintaxe SELECT, consulte Ler dados do OSS. Para otimizar planos de consulta, consulte Otimização de consultas.

Exemplo: Crie uma tabela externa do OSS usando um storage handler personalizado

Este exemplo mapeia uma tabela externa do MaxCompute para o diretório SampleData/ no OSS, utilizando um storage handler personalizado baseado em texto. O handler lê linhas delimitadas por pipe (|) de objetos do OSS e as mapeia para colunas tipadas.

Pré-requisitos

Antes de começar, certifique-se de ter:

Procedimento

  1. Use o MaxCompute Studio para criar as quatro classes Java a seguir. Os links apontam para implementações de referência no SDK Java do Alibaba Cloud:

    Para orientações sobre desenvolvimento de UDFs em Java, consulte Desenvolver uma UDF.

  2. Use o recurso de empacotamento com um clique do MaxCompute Studio para empacotar TextStorageHandler.java e carregue-o como um recurso do MaxCompute. Este exemplo considera que o recurso se chama javatest-1.0-SNAPSHOT.jar. Para etapas de empacotamento e upload, consulte Empacotar, fazer upload e registrar.

    Se o seu storage handler possuir múltiplas dependências, empacote cada uma separadamente e carregue-as como recursos individuais do MaxCompute.
  3. Crie a tabela externa:

    CREATE EXTERNAL TABLE ambulance_data_txt_external
    (
      vehicleId INT,
      recordId INT,
      patientId INT,
      calls INT,
      locationLatitute DOUBLE,
      locationLongtitue DOUBLE,
      recordTime STRING,
      direction STRING
    )
    STORED BY 'com.aliyun.odps.udf.example.text.TextStorageHandler'
    WITH SERDEPROPERTIES (
      'delimiter'='|',
      'odps.properties.rolearn'='acs:ram::<uid>:role/aliyunodpsdefaultrole'
    )
    LOCATION 'oss://oss-cn-hangzhou-internal.aliyuncs.com/oss-mc-test/SampleData/'
    USING 'javatest-1.0-SNAPSHOT.jar';

    A propriedade delimiter define o separador de colunas usado em cada linha dos objetos do OSS. Qualquer string válida é aceita.

    Para verifique a estrutura da tabela após a criação, execute:

    DESC EXTENDED ambulance_data_txt_external;
  4. Leia dados da tabela:

    SELECT recordId, patientId, direction FROM ambulance_data_txt_external WHERE patientId > 25;

    Saída esperada:

    +----------+-----------+-----------+
    | recordid | patientid | direction |
    +----------+-----------+-----------+
    | 1        | 51        | S         |
    | 3        | 48        | NE        |
    | 4        | 30        | W         |
    | 5        | 47        | S         |
    | 7        | 53        | N         |
    | 8        | 63        | SW        |
    | 10       | 31        | N         |
    +----------+-----------+-----------+
  5. Escreva dados na tabela:

    INSERT INTO ambulance_data_txt_external VALUES (1,16,76,1,'46.81006','-92.08174','9/14/2014 0:10','SW');

    Para confirme a escrita, consulte a linha inserida ou verifique se há um novo arquivo no diretório do OSS:

    SELECT * FROM ambulance_data_txt_external WHERE recordId='16';

Perguntas frequentes

Por que o erro ODPS-0123131 ocorre ao ler um campo DATETIME usando um Extractor personalizado?

A causa raiz é java.sql.Date.valueOf(), que aceita apenas strings no formato "yyyy-[m]m-[d]d". Quando o valor do campo inclui um componente de tempo (por exemplo, 2019-11-11 06:43:36), a chamada falha com IllegalArgumentException.

Corrija isso adicionando a biblioteca Joda-Time e usando DateTimeFormat.forPattern() para analisar o valor:

  1. Adicione a dependência Joda-Time ao seu projeto:

    <dependency>
      <groupId>joda-time</groupId>
      <artifactId>joda-time</artifactId>
      <version>2.10</version>
    </dependency>
  2. Importe as classes necessárias:

    import org.joda.time.DateTime;
    import org.joda.time.format.DateTimeFormat;
  3. Substitua a chamada Date.valueOf() por uma análise do Joda-Time:

    record.setDate(index, new Date(DateTime.parse(parts[i], DateTimeFormat.forPattern("yyyy-MM-dd HH:mi:ss")).getMillis()));
  4. Carregue o JAR atualizado do Extractor e o JAR do Joda-Time como recursos do MaxCompute:

    ADD JAR /path/to/text_extractor-1.0-SNAPSHOT.jar;
    ADD JAR /path/to/joda-time-2.10.jar;
  5. Carregue um arquivo de teste no OSS. Formato de linha de exemplo:

    5c661071dba64d5080c91da085ff1073^music-click-fast_forward^26.12.XX.XX^2019-11-11 06:43:36
  6. Consulte a tabela externa para confirme a análise bem-sucedida:

    SELECT * FROM <project_name>.video_play_log;

    Saída esperada:

    +----------------------------------+--------------------------+-------------+---------------------+
    | uuid                             | action                   | ip          | time                |
    +----------------------------------+--------------------------+-------------+---------------------+
    | 5c661071dba64d5080c91da085ff1073 | music-click-fast_forward | 26.12.XX.XX | 2019-11-11 06:43:36 |
    +----------------------------------+--------------------------+-------------+---------------------+