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对象的。

相关推荐
对空六课10 分钟前
指标口径生效时间的版本查询实现
大数据·服务器·前端·算法·数据分析
liliangcsdn11 分钟前
服务消费参数指标的解析与应用
大数据
对空六课15 分钟前
RFM分层边界变化的回溯计算
大数据·服务器·前端·数据库·人工智能·算法·数据分析
大大大大晴天28 分钟前
每天认识一个组件:Spark Catalyst
大数据
小蒋观天下42 分钟前
厂区人员徘徊游荡判别——基于时序轨迹速度的逗留行为分级算法落地
大数据·人工智能·深度学习·算法·机器学习·ai大模型
shaibdoio1 小时前
瞬维AI技术拆解:AI获客智能体的双层漏斗算法原理
大数据·人工智能·算法
ZXCher1 小时前
危废库应急响应系统设计:越华环保集团泄漏/火灾场景下的自动化与硬件联动架构
大数据·架构·自动化
野生数据人2 小时前
ES DSL 转 SQL 速查表:20 条子句对照 + 一条能直接跑的改写示例
大数据·数据库
野生数据人2 小时前
采集链路改投 Doris 速查手册:三条路径对照、output 配置项清单、报错处理表
大数据·数据库
真上帝的左手3 小时前
27. 数据产品-数据治理-11.完整岗位体系
大数据·数据治理·数据架构