Trino是如何读取ORC文件的

ORC文件介绍

什么是ORC文件

ORC的全称是(Optimized Row Columnar),ORC文件格式是一种Hadoop生态圈中的列式存储格式,它的产生早在2013年初,最初产生自Apache Hive,用于降低Hadoop数据存储空间和加速Hive查询速度。ORC文件是以二进制的方式存储的,不可以直接读取,但由于ORC的自描述特性,其读写不依赖于 Hive Metastore 或任何其他外部元数据。本身存储了文件数据、数据类型及编码信息。因为文件是自包含的,所以读取ORC文件数据无需考虑用户使用环境。ORC具有以下一些优势:

  1. ORC是列式存储,有多种文件压缩方式,并且有着很高的压缩比。
  2. 文件是可切分(Split)的。因此,在Hive中使用ORC作为表的文件存储格式,不仅节省HDFS存储资源,查询任务的输入数据量减少,使用的MapTask也就减少了。
  3. 提供了多种索引,row group index、bloom filter index。

ORC文件结构

ORC文件由三大部分组成:Header, FileTail 和 Stripes

在整个orc文件的最开始,会有orc三个字,用来标识文件类型,这个可以称为文件的Header

Stripes

一个ORC文件包含一个或多个stripe, 一组行形成一个stripe,每次读取文件是以行组为单位。每个stripe之间相互独立。细节架构如下图所示

每个Stripe包含以下三个部分:

  1. Index Data:各column的最大值,最小值,及每个数据段在stripe中的位置
  2. Row Data:实际存储数据的单元,利用列存储原理,对不同列可以实现不同的压缩方案,所有的列数据可以组成行数据。
  3. Stripe Footer:它包含每列的编码形式、Stream的元信息

Stream保存了用户真正关心的业务数据内容,这也是ORC列式存储的根本所在:正如上面的架构图一样,一个大文件由各Stripe分割,每个Stripe负责一个或多个行组(一个行组默认10000行),在一个Stripe范围内,各列的数据内容以Stream的形式按列存储。为了描述每个Stream,ORC以字节为单位存储Stream的类型、列ID和Stream的大小。每个Stream中存储内容的详细信息取决于列的类型和编码。也就是说,在一个Stripe中的每一列都可能有多个表示不同信息的Stream。

FileTail

FileTail包含以下三个部分:Postscript, File Footer, File Metadata

Postscript: 文件的最后一个字节保存着PostScript的长度,它的长度不会超过256字节,PostScript提供了解释文件其余部分的必要信息,包括文件的 Footer 和 Metadata 部分的长度、文件的版本以及使用的一般压缩类型(例如 none、zlib 或 snappy)、文件内部每个压缩块的最大长度(每次分配内存的大小)以及一些版本信息。

File Footer: 包含文件主体的布局,类型架构信息,行数和每个列的统计信息。

File Metadata: 该部分包含各Stripe级别粒度的列统计信息,File Footer中的列统计信息是文件级别的

官网链接:orc.apache.org/specificati...

Trino读取ORC文件

以TableScanOperator读取数据的流程为例:

整个读取的调用链路流程还是挺清晰明了的,但最重要的是StripeReader是如何去读取构造Stripe文件的,需要分析代码来研究

读取各个列的数据

首先通过StripeFooter获取需要读取的各个列的streams

接着将目标streams转换为一组<StreamId, DiskRange>的map, DiskRange代表这个stream的offset和length, 标明stream的位置。然后调用readDiskRanges方法去读取目标位置的数据

在readDiskRanges方法中,会把每个stream的offset转换为orc file中的绝对值offset,然后调用orcDataSource去构造每个stream的orcDataReader

在orcDataSource的readFully方法中,会根据每个diskRange的length, 区分为smallRagne和largeRange, 默认的区分大小为8M, 然后采用不同的方法进去读取

对于smallRanges, 会通过mergeAdjacentDiskRanges方法判断相邻的两个smallRange,如果merge之后的diskrange小于8M,且该两个smallRange的距离小于默认值1M,则合并成新的diskRange。

然后判断是否设置了lazy read(默认为True), 如果是,则给每个diskRange构造对应的MergedOrcDataReader, 在真正使用数据的时候才会去读取。否则通过直接从hdfs或者其他数据源接口读取数据放在内存中,给每个diskRange构造对应的MemoryOrcDataReader。

对于largeRanges, 会对每个largeRange构造对应的DiskOrcDataReader。在DiskOrcDataReader中,默认每次最大读取8M的数据。

利用索引来进行过滤

读取完数据后会从ORC文件中读取RowGroupIndex和BloomFilter

RowGroupIndex其实就是min max索引,就像之前提到的,index data中会存有每个列的最大值和最小值,就用该数据来构造RowGroupIndex。当判断条件中有大于小于时,则可用RowGroupIndex来进行过滤,而当查询条件中包含对某个列的等值判断时,就可以使用BloomFilter中判断是否包含该值,进行判断是否进行过滤。

在对stripe使用RowGroupIndex和BloomFilter过滤完成后,剩下的selectedRowGroups就是我们真正要读的数据

构造新的RowGroups和Stripe

根据上一步拿到的过滤后的数据来构造新的RowGroups和Stripe作为返回数据。

最后从每个列的columnReader中读取数据,每个列封装为一个block,多个block组合成page对象。Trino中对数据的操作就是基于这个page对象的。

相关推荐
IT_102416 分钟前
Spring Boot的Security安全控制——应用SpringSecurity!
大数据·spring boot·后端
盟接之桥42 分钟前
国产替代新标杆|盟接之桥EDI软件让中国制造连接世界更安全、更简单、更有底气
大数据
RestCloud2 小时前
ETLCloud中数据生成规则使用技巧
大数据·服务器·数据库·etl·数字化转型·数据处理·集成平台
Jack_hrx8 小时前
从0到1构建高并发秒杀系统:实战 RocketMQ 异步削峰与Redis预减库存
大数据·rocketmq·高并发·秒杀系统实战·异步削峰
Double@加贝9 小时前
MaxCompute的Logview分析详解
大数据·阿里云·dataworks·maxcompute
Mikhail_G11 小时前
Python应用八股文
大数据·运维·开发语言·python·数据分析
Elastic 中国社区官方博客15 小时前
JavaScript 中的 ES|QL:利用 Apache Arrow 工具
大数据·开发语言·javascript·elasticsearch·搜索引擎·全文检索·apache
lifallen17 小时前
Flink task、Operator 和 UDF 之间的关系
java·大数据·flink
源码宝19 小时前
智慧工地云平台源码,基于微服务架构+Java+Spring Cloud +UniApp +MySql
java·大数据·源码·智慧工地·智能监测·智能施工
XiaoQiong.Zhang19 小时前
简历模板3——数据挖掘工程师5年经验
大数据·人工智能·机器学习·数据挖掘