Apache Arrow Parquet存储与使用

 更新时间:2023年08月30日 09:14:55   作者:龚正阳  
这篇文章主要为大家介绍了Apache Arrow Parquet存储与使用原理详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪

简介

Parquet是一种高效的列式存储格式,广泛用于大数据系统中的数据仓库和数据管理工具中,旨在提高数据分析的性能和效率,能够更好地支持数据压缩和列式查询,同时兼顾读写速度和数据大小

初衷

为了让 Hadoop 生态系统中的任何项目都能利用压缩、高效的列式数据表示的优势

技术与原理

基于列存储和压缩技术,每一列的数据通过一系列压缩算法进行压缩,然后存储到文件系统中,这种方式能够避免存储冗余数据,并且能够使查询只涉及到所需的列,从而大大提高查询效率

相关术语

  • Blockhdfs Block):hdfs中的数据块
  • Filehdfs 文件,包含文件的元数据,不需要包含实际的数据
  • Row group/行组:将数据水平划分为Row group
  • Column chunk:特定列的数据块,它们位于特定的行组中,并保证在文件中是连续的
  • Page:列块被分为页,页面在概念上是一个不可分割的单元(就压缩和编码而言),列块中可以有多种交错的页面类型,Page为了让数据读取的粒度足够小,便于单条数据或小批量数据的查询

从层次结构上看,文件由一个或多个行组组成,行组的每列恰好包含一个列块,列块包含一页或多页

结构图如下

文件格式如下

4-byte magic number "PAR1"
<Column 1 Chunk 1 + Column Metadata>
<Column 2 Chunk 1 + Column Metadata>
...
<Column N Chunk 1 + Column Metadata>
<Column 1 Chunk 2 + Column Metadata>
<Column 2 Chunk 2 + Column Metadata>
...
<Column N Chunk 2 + Column Metadata>
...
<Column 1 Chunk M + Column Metadata>
<Column 2 Chunk M + Column Metadata>
...
<Column N Chunk M + Column Metadata>
File Metadata
4-byte length in bytes of file metadata
4-byte magic number "PAR1"

Header

Header的内容很少,只有4个字节,本质是一个magic number,用来指示文件类型

PAR1:普通的Parquet文件

PARE: 加密过的Parquet文件

File Body

实际存储数据,包含Column ChunkColumn Metadata

Footer

  • 包含了诸如schemaBlockoffsetsizeColumn Chunkoffsetsize等所有重要的元数据
  • 承担了整个文件入口的职责,读取Parquet文件的第一步就是读取Footer信息,转换成元数据之后,再根据这些元数据跳转到对应的blockcolumn,读取真正所要的数据

Index

IndexParquet文件的索引块,主要为了支持谓词下推(Predicate Pushdown)功能

谓词下推是一种优化查询性能的技术,简单地来说就是把查询条件发给存储层,让存储层可以做初步的过滤,把肯定不满足查询条件的数据排除掉,从而减少数据的读取和传输量

Parquet索引类型

  • Max-MinMax-Min索引是对每个Page都记录它所含数据的最大值和最小值,这样某个Page是否不满足查询条件就可以通过这个Pagemaxmin值来判断
  • BloomFilter索引: 针对value比较稀疏,max-min范围比较大的列,用Max-Min索引的效果就不太好,BloomFilter可以克服这一点,同时也可以用于单条数据的查询

rust读写Parquet文件

依赖项目

https://github.com/apache/arrow-r

修改Cargo.toml如下

[dependencies]
parquet = "46.0.0"
parquet_derive = "46.0.0"

修改main.rs

use std::convert::TryFrom;
use std::{fs, path::Path};
use parquet::file::reader::SerializedFileReader;
use parquet::file::writer::SerializedFileWriter;
use parquet::record::RecordWriter;
use parquet_derive::ParquetRecordWriter;
const PARQUET_FILEPATH: &str = "./target/sample.parquet";
#[derive(ParquetRecordWriter)]
struct ACompleteRecord<'a> {
    pub a_bool: bool,
    pub a_str: &'a str,
}
fn write() {
    let path = Path::new(PARQUET_FILEPATH);
    let file = fs::File::create(path).unwrap();
    let samples = vec![
        ACompleteRecord {
            a_bool: true,
            a_str: "I'm true",
        },
        ACompleteRecord {
            a_bool: false,
            a_str: "I'm false",
        },
    ];
    let schema = samples.as_slice().schema().unwrap();
    let mut writer = SerializedFileWriter::new(file, schema, Default::default()).unwrap();
    let mut row_group = writer.next_row_group().unwrap();
    samples
        .as_slice()
        .write_to_row_group(&mut row_group)
        .unwrap();
    row_group.close().unwrap();
    writer.close().unwrap();
}
fn read() {
    let rows = [PARQUET_FILEPATH]
        .iter()
        .map(|p| SerializedFileReader::try_from(*p).unwrap())
        .flat_map(|r| r.into_iter());
    for row in rows {
        println!("{}", row.unwrap());
    }
}
fn main() {
    write();
    read();
}

运行

$ cargo run   
   Compiling temp v0.1.0 (/home/gong/rust-work/temp)
    Finished dev [unoptimized + debuginfo] target(s) in 2.26s
     Running `target/debug/temp`
{a_bool: true, a_str: "I'm true"}
{a_bool: false, a_str: "I'm false"}

查看parquet文件

$ cat target/sample.parquet
PAR1,X%a_bool44<X22I'm true     I'm false,I'm true      I'm false
                                                                 5a_str��&�&�I'm true   I'm false       I'm falsI'm tru4�V<H
     rust_schema%a_bool
                       %a_str%L,&<%a_bool44<X��"&�
                                                  5a_str��&�&�I'm true  I'm false��@��(parquet-rs version 46.0.0�PAR1%

阅读参考

Apache parquet document

详解Parquet文件格式原理

以上就是Apache Arrow Parquet存储与使用的详细内容,更多关于Apache Arrow Parquet存储的资料请关注脚本之家其它相关文章!

相关文章

  • 使用@CacheEvict清除指定下所有缓存

    使用@CacheEvict清除指定下所有缓存

    这篇文章主要介绍了使用@CacheEvict清除指定下所有缓存,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2021-12-12
  • Java集合系列之LinkedHashMap源码分析

    Java集合系列之LinkedHashMap源码分析

    这篇文章主要为大家详细介绍了Java集合系列之LinkedHashMap源码分析,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2018-02-02
  • Java实现List去重的几种方法总结

    Java实现List去重的几种方法总结

    这篇文章主要为大家详细介绍了Java中List去重的几种常用方法总结,文中的示例代码讲解详细,具有一定的学习和参考价值,需要的小伙伴可以了解一下
    2023-09-09
  • Java8新特性之接口中的默认方法和静态方法详解

    Java8新特性之接口中的默认方法和静态方法详解

    今天带大家学习的是Java8新特性的相关知识,文章围绕着Java接口中的默认方法和静态方法展开,文中有非常详细的的代码示例,需要的朋友可以参考下
    2021-06-06
  • Java数据结构常见几大排序梳理

    Java数据结构常见几大排序梳理

    Java常见的排序算法有:直接插入排序、希尔排序、选择排序、冒泡排序、归并排序、快速排序、堆排序等。本文详解介绍它们的实现以及图解,需要的可以参考一下
    2022-03-03
  • Java知识梳理之泛型用法详解

    Java知识梳理之泛型用法详解

    从JDK 5.0以后,Java引入了“参数化类型(Parameterized type)”的概念,允许我们在创建集合时再指定集合元素的类型。本文就来和大家深入聊聊Java泛型的使用
    2022-08-08
  • spring boot 监控处理方案实例详解

    spring boot 监控处理方案实例详解

    这篇文章主要介绍了spring boot 监控处理方案的相关资料,非常不错,具有一定的参考借鉴价值,需要的朋友可以参考下
    2018-07-07
  • JAVA使用动态代理对象进行敏感字过滤代码实例

    JAVA使用动态代理对象进行敏感字过滤代码实例

    这篇文章主要介绍了JAVA使用动态代理对象进行敏感字过滤代码实例,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2019-09-09
  • 浅谈spring的重试机制无效@Retryable@EnableRetry

    浅谈spring的重试机制无效@Retryable@EnableRetry

    这篇文章主要介绍了浅谈spring的重试机制无效@Retryable@EnableRetry,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2020-09-09
  • RabbitMQ消息确认机制剖析

    RabbitMQ消息确认机制剖析

    这篇文章主要为大家介绍了RabbitMQ消息确认机制剖析,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2022-08-08

最新评论