Este repositório contém a especificação para definições do Apache Parquet e Apache Thrift para ler e gravar metadados do Parquet.
Apache Parquet é um formato de arquivo de dados de código aberto orientado a colunas, projetado para armazenamento e recuperação eficiente de dados. Ele fornece esquemas de compactação e codificação de alto desempenho para lidar com dados complexos em massa e é compatível com muitas linguagens de programação e ferramentas analíticas.
Criamos o Parquet para disponibilizar as vantagens da representação de dados colunares compactada e eficiente para qualquer projeto no ecossistema Hadoop.
O Parquet é construído do zero com estruturas de dados aninhadas complexas em mente e usa o algoritmo de destruição e montagem de registros descrito no artigo da Dremel. Acreditamos que esta abordagem é superior ao simples nivelamento de espaços de nomes aninhados.
O Parquet foi desenvolvido para suportar esquemas de compactação e codificação muito eficientes. Vários projetos demonstraram o impacto no desempenho da aplicação do esquema correto de compactação e codificação aos dados. Parquet permite que esquemas de compactação sejam especificados por coluna e é preparado para o futuro para permitir a adição de mais codificações à medida que são inventadas e implementadas.
Parquet foi construído para ser usado por qualquer pessoa. O ecossistema Hadoop é rico em estruturas de processamento de dados e não estamos interessados em ter favoritos. Acreditamos que um substrato de armazenamento colunar eficiente e bem implementado deve ser útil para todas as estruturas sem o custo de dependências extensas e difíceis de configurar.
O projeto parquet-format
contém especificações de formato e definições Thrift de metadados necessários para ler corretamente os arquivos Parquet.
O projeto parquet-java
contém vários submódulos, que implementam os componentes principais de leitura e gravação de um fluxo de dados aninhado e orientado a colunas, mapeiam esse núcleo no formato parquet e fornecem formatos de entrada/saída Hadoop, carregadores Pig e outros. utilitários baseados em java para interagir com Parquet.
O projeto parquet-compatibility
contém testes de compatibilidade que podem ser usados para verificar se implementações em diferentes linguagens podem ler e gravar os arquivos umas das outras.
Os recursos Java podem ser construídos usando mvn package
. A versão estável atual deve estar sempre disponível no Maven Central.
Recursos de economia C++ podem ser gerados via make.
O Thrift também pode ser gerado por código em qualquer outra linguagem compatível com o Thrift.
Bloco (bloco HDFS): Significa um bloco no HDFS e o significado permanece inalterado para descrever este formato de arquivo. O formato de arquivo foi projetado para funcionar bem em HDFS.
Arquivo: um arquivo HDFS que deve incluir os metadados do arquivo. Na verdade, não precisa conter os dados.
Grupo de linhas: um particionamento lógico horizontal dos dados em linhas. Não há estrutura física garantida para um grupo de linhas. Um grupo de linhas consiste em um bloco de coluna para cada coluna do conjunto de dados.
Pedaço de coluna: um pedaço de dados de uma coluna específica. Eles residem em um grupo de linhas específico e têm garantia de serem contíguos no arquivo.
Página: os pedaços de coluna são divididos em páginas. Uma página é conceitualmente uma unidade indivisível (em termos de compactação e codificação). Pode haver vários tipos de páginas intercalados em um bloco de coluna.
Hierarquicamente, um arquivo consiste em um ou mais grupos de linhas. Um grupo de linhas contém exatamente um pedaço de coluna por coluna. Os pedaços de coluna contêm uma ou mais páginas.
Este arquivo e a definição do Thrift devem ser lidos juntos para entender o formato.
4-byte magic number "PAR1"
<Column 1 Chunk 1>
<Column 2 Chunk 1>
...
<Column N Chunk 1>
<Column 1 Chunk 2>
<Column 2 Chunk 2>
...
<Column N Chunk 2>
...
<Column 1 Chunk M>
<Column 2 Chunk M>
...
<Column N Chunk M>
File Metadata
4-byte length in bytes of file metadata (little endian)
4-byte magic number "PAR1"
No exemplo acima, existem N colunas nesta tabela, divididas em M grupos de linhas. Os metadados do arquivo contêm os locais de todos os locais de início dos blocos de coluna. Mais detalhes sobre o que está contido nos metadados podem ser encontrados na definição do Thrift.
Os metadados do arquivo são gravados após os dados para permitir a gravação em uma única passagem.
Espera-se que os leitores leiam primeiro os metadados do arquivo para encontrar todos os pedaços de colunas nos quais estão interessados. Os pedaços de colunas devem então ser lidos sequencialmente.
Existem dois tipos de metadados: metadados de arquivo e metadados de cabeçalho de página. Todas as estruturas de economia são serializadas usando o TCompactProtocol.
Os tipos suportados pelo formato de arquivo devem ser os mínimos possíveis, com foco em como os tipos afetam o armazenamento em disco. Por exemplo, inteiros de 16 bits não são explicitamente suportados no formato de armazenamento, pois são cobertos por inteiros de 32 bits com uma codificação eficiente. Isso reduz a complexidade da implementação de leitores e gravadores para o formato. Os tipos são:
Os tipos lógicos são usados para estender os tipos que o parquet pode armazenar, especificando como os tipos primitivos devem ser interpretados. Isso mantém o conjunto de tipos primitivos no mínimo e reutiliza as codificações eficientes do parquet. Por exemplo, strings são armazenadas com o tipo primitivo BYTE_ARRAY com uma anotação STRING. Essas anotações definem como decodificar e interpretar ainda mais os dados. As anotações são armazenadas como campos LogicalType
nos metadados do arquivo e são documentadas em LogicalTypes.md.
Parquet armazena estatísticas mínimas/máximas em vários níveis (como Pedaço de Coluna, Índice de Coluna e Página de Dados). A comparação de valores de um tipo obedece às seguintes regras:
Cada tipo lógico possui uma ordem de comparação especificada. Se uma coluna for anotada com um tipo lógico desconhecido, as estatísticas não poderão ser usadas para remover dados. A ordem de classificação dos tipos lógicos está documentada na página LogicalTypes.md.
Para tipos primitivos, aplicam-se as seguintes regras:
BOOLEAN - falso, verdadeiro
INT32, INT64 – Comparação assinada.
FLOAT, DOUBLE - Comparação assinada com tratamento especial de NaNs e zeros assinados. Os detalhes estão documentados na definição Thrift na união ColumnOrder
. Eles estão resumidos aqui, mas a definição de Thrift é considerada oficial:
+0.0
deverá ser escrito no campo de estatísticas máximas.-0.0
deverá ser escrito no campo de estatísticas mínimas.Para compatibilidade com versões anteriores ao ler arquivos:
BYTE_ARRAY e FIXED_LEN_BYTE_ARRAY - comparação lexicográfica de bytes não assinados.
Para codificar colunas aninhadas, Parquet usa a codificação Dremel com níveis de definição e repetição. Os níveis de definição especificam quantos campos opcionais no caminho da coluna estão definidos. Os níveis de repetição especificam em qual campo repetido no caminho o valor é repetido. Os níveis máximos de definição e repetição podem ser calculados a partir do esquema (ou seja, quanto aninhamento existe). Isto define o número máximo de bits necessários para armazenar os níveis (os níveis são definidos para todos os valores na coluna).
Duas codificações para os níveis são suportadas BIT_PACKED e RLE. Somente RLE é usado agora, pois substitui BIT_PACKED.
A nulidade é codificada nos níveis de definição (que são codificados no comprimento da execução). Valores NULL não são codificados nos dados. Por exemplo, em um esquema não aninhado, uma coluna com 1.000 NULLs seria codificada com codificação de comprimento de execução (0, 1.000 vezes) para os níveis de definição e nada mais.
Para páginas de dados, as 3 informações são codificadas consecutivamente, após o cabeçalho da página. Nenhum preenchimento é permitido na página de dados. Em ordem temos:
O valor de uncompressed_page_size
especificado no cabeçalho é para todas as 3 peças combinadas.
Os valores codificados para a página de dados são sempre obrigatórios. Os níveis de definição e repetição são opcionais, com base na definição do esquema. Se a coluna não estiver aninhada (ou seja, o caminho para a coluna tiver comprimento 1), não codificamos os níveis de repetição (teria sempre o valor 1). Para dados necessários, os níveis de definição são ignorados (se codificados, sempre terão o valor do nível máximo de definição).
Por exemplo, no caso em que a coluna não é aninhada e é obrigatória, os dados na página são apenas os valores codificados.
As codificações suportadas estão descritas em Encodings.md
Os codecs de compactação suportados são descritos em Compression.md
Os pedaços de coluna são compostos de páginas escritas consecutivamente. As páginas compartilham um cabeçalho comum e os leitores podem pular páginas nas quais não estão interessados. Os dados da página seguem o cabeçalho e podem ser compactados e/ou codificados. A compactação e a codificação são especificadas nos metadados da página.
Um pedaço de coluna pode ser parcial ou totalmente codificado por dicionário. Isso significa que os índices do dicionário são salvos nas páginas de dados em vez dos valores reais. Os valores reais são armazenados na página do dicionário. Veja detalhes em Encodings.md. A página do dicionário deve ser colocada na primeira posição do bloco da coluna. No máximo uma página de dicionário pode ser colocada em um bloco de coluna.
Além disso, os arquivos podem conter um índice de coluna opcional para permitir que os leitores pulem as páginas com mais eficiência. Consulte PageIndex.md para obter detalhes e o raciocínio por trás de adicioná-los ao formato.
Páginas de todos os tipos podem ser verificadas individualmente. Isso permite desabilitar somas de verificação no nível do arquivo HDFS, para melhor suportar pesquisas de linha única. As somas de verificação são calculadas usando o algoritmo CRC32 padrão - como usado, por exemplo, no GZip - na representação binária serializada de uma página (não incluindo o próprio cabeçalho da página).
Se os metadados do arquivo estiverem corrompidos, o arquivo será perdido. Se os metadados da coluna estiverem corrompidos, esse pedaço de coluna será perdido (mas os pedaços de coluna para esta coluna em outros grupos de linhas estão corretos). Se o cabeçalho de uma página estiver corrompido, as páginas restantes nesse bloco serão perdidas. Se os dados de uma página estiverem corrompidos, essa página será perdida. O arquivo será mais resistente à corrupção com grupos de linhas menores.
Extensão potencial: com grupos de linhas menores, o maior problema é colocar os metadados do arquivo no final. Se ocorrer um erro ao gravar os metadados do arquivo, todos os dados gravados ficarão ilegíveis. Isso pode ser corrigido gravando os metadados do arquivo a cada enésimo grupo de linhas. Cada metadado de arquivo seria cumulativo e incluiria todos os grupos de linhas gravados até o momento. Combinando isso com a estratégia usada para arquivos rc ou avro usando marcadores de sincronização, um leitor poderia recuperar arquivos parcialmente gravados.
O formato é explicitamente projetado para separar os metadados dos dados. Isso permite dividir colunas em vários arquivos, bem como fazer com que um único arquivo de metadados faça referência a vários arquivos parquet.
Existem muitos locais no formato para extensões compatíveis:
Parquet Thrift IDL reserva o ID de campo 32767
de cada estrutura Thrift para extensões. O tipo (Thrift) deste campo é sempre binary
.
O apache/parquet-testing contém um conjunto de arquivos Parquet para fins de teste.
Comente sobre o assunto e/ou entre em contato com a mailing list parquet-dev com suas dúvidas e ideias. Mudanças nesta definição de formato principal são propostas e discutidas em profundidade na lista de discussão. Você também pode estar interessado em contribuir para o subprojeto Parquet-Java, que contém todas as implementações e APIs do lado Java. Veja a seção "Como Contribuir" do projeto Parquet-Java
Nós e a comunidade de desenvolvedores Parquet seguimos um código de conduta conforme descrito pelo Twitter OSS: https://github.com/twitter/code-of-conduct/blob/master/code-of-conduct.md.
Copyright 2013 Twitter, Cloudera e outros colaboradores.
Licenciado sob a Licença Apache, Versão 2.0: http://www.apache.org/licenses/LICENSE-2.0