0
点赞
收藏
分享

微信扫一扫

学习parquet

嚯霍嚯 2022-01-06 阅读 52
大数据

参考文档

https://parquet.apache.org/documentation/latest/ : 官网
https://blog.csdn.net/Night_ZW/article/details/108359619 
https://cnblogs.com/panpanwelcome/p/10248990.html
https://static.googleusercontent.com/media/research.google.com/zh-CN//pubs/archive/36632.pdf : dermel论文
https://www.cnblogs.com/ulysses-you/p/7985240.html
zhuanlan.zhihu.com/p/111822325

学习parquet文件格式,先来了解列存储和行存储

  • 行存储:一条记录存储在连续的磁盘上
  • 列存储:一条记录存储在磁盘的不同位置,但是整个关系(表)的一列存储在连续的磁盘上.

了解oltp和olap的典型场景

  • tp
    • 单条记录的增删改查,通常是整条记录
    • 频繁的插入或更新;
  • ap
    • 某几列的整表统计.分组,排序,聚合等

分析

  • 单条记录的增删改查
    • 行存储通过索引找到数据直接修改数据,但是列存储却需要将记录分成列,再对每列操作.操作数指数上升
  • 统计
    • 行存储需要整表扫描并计算
    • 列存储
      • 选择部分列:不需要所有的列都读出来,读数少
      • 过滤不需要的数据
      • 同列同类型:高压缩,每列都可以选择不同的压缩方式,数据量更少,缓存效果更高等
      • 向量计算
  • 行列混合存储
    • 明面上是行存储,实际用列存储;
    • parquet,orc

parquet

  • 新型列式存储格式;与平台,语言无关;灵感来源Google Dremel论文;支持嵌套式存储格式;

  • 在这里插入图片描述

  • 基本架构如上图:java学习可以maven仓库搜parquet

  • <!-- https://mvnrepository.com/artifact/org.apache.parquet/parquet-avro -->
    <dependency>
        <groupId>org.apache.parquet</groupId>
        <artifactId>parquet-avro</artifactId>
        <version>1.12.2</version>
    </dependency>
    

glossary

结构图:

在这里插入图片描述

引用一位知乎大佬的图

在这里插入图片描述

元数据

  • 文件元数据
    • 主要存储schema等;源码当中有一个ParquetMetaData包含了(FileMetaData和BlockMetaData)
  • 行组元数据
    • 行数量,数据量大小,列块元数据等;
  • 列块元数据
    • offset,encoding等
    • 统计信息:valueCount,totalSize,max,min,numNulls等
  • 在这里插入图片描述

读写流程

  • 从后往前读,读取magic Number,判断是否是一个parquet文件;读取Footer Length,读取元数据的大小,计算元数据的起始位置;读取元数据.
  • 通过列块元数据过滤更多的数据(max,min)(predicate pushdown filter);
    • 字典页:假设存储的数据类型是String,则对string编码,string1 -> 1,string2 -> 2;这样存储的数据就是1211222这样;再存储字段映射关系即可.

Striping/assembly算法

  • schema树形结构图
  • 在这里插入图片描述

parquet对嵌套格式的支持,源于dermel论文

在这里插入图片描述

基于上面的图

  • message:相当于表
  • 里面的字段分三种
    • 重复数
      • 三种:required(必须有的),optional(可以为null),repeated(重复的,可以有多条数据)
    • 字段类型:普通类型和复杂类型(group);普通类型就是标准类型,复杂类型,就是表示嵌套结构,下一层还有字段;
    • 字段名
    • 说明:上图links.forward字段,第一条数据有3个forward;所以存储3条数据:repeated表示是可以重复的
      • 个人误区:之前以为forward这样的list会存储到多个列中,但是实际只存一个列多行;

definition levels 和repetion levels

数据存储好后,如何读取数据将数据还原

存储中,除了存储了值还需要存储definition levels(d)和repetion levels®

  • repetion levels:标识一个重复深度.0表示新记录;只记录repeated
    • 以Name.Language.code为例
      • 第一条数据起始是0,第二条数据重复Name,Language,所以是2,第三条重复Name,是1,第四条也是重复Name是1,第五条新数据0
  • definition levels:嵌套结构中,repeted会有多行数据,表示一个定义等级;required是必须定义的,所以是不需要的.
    • Name.Url为例
      • 前面两条都定义了Name和Url都是2.第三条定义了Name没有定义Url.所以是1
    • 再以Name.Language.Country为例
      • 第一条数据定义了Name.Language.Country所以是3,第二条定义了Name.Language是2,第三条定义Name是1,然后根据层级是3和1;
    • Name.Language.code
      • code的定义等级只有2,required不记录等级;可以对比country为3.

我们该如何根据这些信息拼凑出真正的数据呢

1. 假设要取一条数据.通过0可以判断这是一条数据.
2. 如何将这一条数据根据schema还原成原来的样子
3. 读取DocId,赋值
	读取Links.Backward:读第一条数据赋值,读第二条数据判断r=1,表示重复1(第一个repeated),即重复Backward,增加一条Backword;
	读取Links.Forward:读取第一条,赋值
	读取Name.Language.code:读取第一条赋值,第二条,r=2,即重复深度为Language;
	读取Name.Language.Country:读取第二条 r=2,重复深度为Language
	...

日常使用

1. 一般是作为hive的存储格式 create table t(id int) stored as parquet;
2. hive修改列名后读取的数据是null
	parquet.column.index.access = true
	可以在建表时加入以上参数;hive默认的读取parquet文件是按照名称读取的,所以按照名称自然是查不到的.因为parquet本身是不支持修改的.
	这个参数的功能是使hive读取parquet文件时使用序列号读取.这样,更改了名字也能读
	orc默认是按序列号读取的.
	可以直接用spark-shell读取文件,会发现读取出来的是原字段名;
3. hive修改列类型后直接导致查询出错
	presto和hive查询会报错,而spark不会
	presto(trino)默认使用hive的元数据读取文件
		设置参数:hive.parquet.use_column_names=true;使用文件schema读取文件,而不是hive MetaData
	spark对parquet的文件做了特殊优化,spark读取parquet文件会按照文件的schema读取,而且当hive元数据和schema不一致时做优化.
	hive:用原始数据重新覆盖表即可
	

	
举报

相关推荐

0 条评论