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 |
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 |
|
|
Sim |
Nome de classe totalmente qualificado do seu storage handler personalizado, implementado como uma UDF do MaxCompute. Consulte Desenvolver UDFs. |
|
|
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. |
|
|
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:
Um bucket e uma pasta do OSS na mesma região do seu projeto do MaxCompute. Consulte Crie um bucket e Gerencie pastas. O MaxCompute cria pastas do OSS automaticamente durante a execução de instruções SQL; portanto, a criação manual é opcional.
Permissão de acesso ao OSS concedida via conta Alibaba Cloud, usuário do Resource Access Management (RAM) ou função do RAM. Consulte Autorizar acesso no modo STS para o OSS
A permissão
CreateTableno projeto do MaxCompute. Consulte Permissões do MaxCompute
Procedimento
-
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.
-
Use o recurso de empacotamento com um clique do MaxCompute Studio para empacotar
TextStorageHandler.javae carregue-o como um recurso do MaxCompute. Este exemplo considera que o recurso se chamajavatest-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.
-
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
delimiterdefine 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; -
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 | +----------+-----------+-----------+ -
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:
-
Adicione a dependência Joda-Time ao seu projeto:
<dependency> <groupId>joda-time</groupId> <artifactId>joda-time</artifactId> <version>2.10</version> </dependency> -
Importe as classes necessárias:
import org.joda.time.DateTime; import org.joda.time.format.DateTimeFormat; -
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())); -
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; -
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 -
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 | +----------------------------------+--------------------------+-------------+---------------------+