Apache Iceberg 中引入索引提升查询性能

news2024/12/27 2:20:03

动手点关注

9e995669d6337ab0fa18ec24f4ce2879.gif

干货不迷路

‍Apache Iceberg 是一种开源数据 Lakehouse 表格式,提供强大的功能和开放的生态系统,如:Time travel,ACID 事务,partition evolution,schema evolution 等功能。

本文将讨论火山引擎EMR团队针对 Iceberg 组件的优化思路,通过引入索引来提高查询性能。

采用 Iceberg 构建数据湖仓

火山引擎 E-MapReduce(简称 EMR)是火山引擎数智平台(VeDI)旗下的云原生开源大数据平台产品, 提供了企业级的 Hadoop、Spark、Flink、Hive、Presto、Kafka、StarRocks、Doris、Hudi、Iceberg 等大数据生态组件,100% 开源兼容,可以帮助企业快速构建企业级大数据平台,降低运维门槛。秉承业界领先的 EMR Stateless 理念,火山引擎 EMR 可以实现集群级别的弹性伸缩,即无业务需求时释放集群,有业务需求时再拉起集群,配合智能化的冷热数据分层存储能力,助力企业在大数据基建领域进一步降本提效。

基于火山引擎 EMR 产品,可以构建数据湖仓、近实时数仓、实时数仓等场景。例如,使用 Iceberg 构建数据湖仓,从 ODS 到 DWD 等不同的分层进行建模,将数据 HFDS 或 TOS(火山引擎对象存储产品)上,然后采用 Trino 或者 Spark 去做分析。‍

894e657af3c42ad57684150a514a3fcd.png

如何加速查询性能,使其尽可能接近专门的分布式数仓(如 ClickHouse 等),是需要思考和探究的问题。

索引是业界常用的提高查询性能的手段之一,针对 Iceberg 我们也采用了增加索引的方式。对常用的列字段构建 Index,在进行 table scan 时利用 Index 只返回匹配的数据,降低匹配数据量,从而大大提高查询性能。

Iceberg 介绍

介绍 Iceberg Index 功能之前,我们先简单介绍下 Iceberg 的架构。Iceberg 具有分层的元数据架构,如下如所示。

3795a10ac1f40c8f9875c55e8a82ecb4.png

Spark、Presto、Flink 等多种引擎读取 Iceberg 的数据,就是利用分层的元数据找到 data file 列表。例如,Spark 引擎解析 SQL 语句,然后调用 Iceberg 的接口,获取 data file 并进行 task 切分。

3320bdf8de0c9fece68379fe62a0799f.png

在 Manifest file 中记录了 data file 中字段的最大值和最小值。

"data_file": {
        "content": 0,
        "file_path": "hdfs://emr-cluster/warehouse/hive/db.db/sample/data/ts_day=2020-12-31/category=diamond/00000-0-220aa9a6-4530-499f-9450-da946d667624-00001.parquet",
        "file_format": "PARQUET",
        ......
        "lower_bounds": {
                "array": [{
                        "key": 1,
                        "value": "\u0006\u0000\u0000\u0000"
                }, {
                        "key": 2,
                        "value": "diamond"
                }, {
                        "key": 3,
                        "value": "\u0000\u0004ÜÅ·\u0005\u0000"
                }]
        },
        "upper_bounds": {
                "array": [{
                        "key": 1,
                        "value": "\u0007\u0000\u0000\u0000"
                }, {
                        "key": 2,
                        "value": "diamond"
                }, {
                        "key": 3,
                        "value": "\u0000¨odÆ·\u0005\u0000"
                }]
        },
        ......
}

利用这些信息,可以进行 data file 级别的初步过滤,把不符合条件的 data file 过滤掉,进而减少一部分数据的读取。

实现索引的必要性

既然 Iceberg 已经提供 data file 级别的过滤。为什么我们还需要引入索引呢?以下面例子进行介绍,左边两个表格分别是 data file 文件里面的内容,右边表格是 data file 对应的 manifest file。

096c06201cfed01b29b83400080fe87a.png

针对SELECT * FROM table WHERE age > 50,利用 min-max 统计信息,很容易发现 data file 1 中没有满足条件的数据,因此 data file 1 就不会参与计算。

但是针对多维分析,如name = 'LiLy' AND age > 30,利用nameage的min-max的统计信息分别对条件name = 'LiLy'age > 30进行判断,得到 data file 1 和 data file 2 都满足条件。然而,仔细分析 data file 1 和 data file 2 的数据,并不存在符合条件的数据,因此 min-max 过滤效果不太理想。所以通过引入合适的索引功能,可以提高 data skipping 的概率,提高查询性能。

1.  首先探究索引类型

索引类型有多种,如 BloomFilter、Ribbon Filter、Dictionary Index、BitMap 等。为了满足多维分析场景,我们选择了[Range-Encoded BitMap]https://www.featurebase.com/blog/range-encoded-bitmaps ( Base-2, Bit-sliced Index),可适用于高基数场景,满足=、<、>、IN、BETWEEN 等操作的多维分析。

例如,对上面的 name 和 age 两列分别计算索引信息。由于 name 属于字符串类型,需要先进行字典编码再进行计算索引信息。采用 Range-Encoded 技术,根据数据的二进制相关信息以及对应的 pos 信息生成索引数据。利用索引数据分析得到,同时满足name = 'LiLy'age > 30的数据不在同一行,恰好可利用 Range-Encoded 的交并运算将数据进行过滤掉,因此 data file 1 不用参与计算。

也就是说,BitMap 的交并运算可以更好地在复杂过滤条件的情况下过滤掉更多的数据文件。

10b32d37dd072615a7627cf196798aa3.png

2.  接下来探究索引的粒度。

Iceberg 提供的 min-max,也是一种文件级别的索引。文件级别的索引就是根据 filter 条件过滤掉不符合条件的 data file。文件级别的索引可适用于多种文件类型,但这种粒度比较粗,只要 data file 中有一条数据符合条件,该 data file 中的数据就会全部读取出来参与计算,从而影响 SQL 的查询性能。

对于 Parquet、ORC 的文件格式,提供有 file chunk 的概念(row group or stripe),我们完全可以按照 row group / stripe 粒度,对数据进行过滤。(为了方便描述,我们将 row group 和 stripe 统称 split。)

如:SQL语句:SELECT * FROM table WHERE col_1> v1 AND col_2 = v2,其中对 col_1 字段和 col_2 字段已构建 Index 信息。现在利用索引对 SQL 语句作用。

7e44d3c8b57e0e4e92ced81333bcc95b.png

SQL 语句解析后,将符合条件的 data file 列表进行切分后,得到很多 split 的列表。利用索引,分析 split 中数据是否满足条件,如果不满足则跳过。如上图 data file 列表切分后,得到数万级别数量的 split 列表。将索引数据作用在 split1,发现 split1 中没有同时col_1> v1 AND col_2 = v2满足条件的数据,该 split1 中的数据就不会参与计算。最后处理后,只得到了少量的 split 列表,数据过滤度达到 10% 以上,查询性能有明显提升。

因此,采用 row group / stripe 级别的细粒度索引,可以过滤大部分数据。

细粒度索引实现逻辑

Iceberg 元数据中 manifest file 中除了提供 min-max 等统计信息,还提供有 split 相关信息:"split_offsets":{"array":[4,...]},极大方便我们实现 row group / stripe 级别的细粒度索引。

  1. 提供索引的构建 API

Iceberg 中提供构建索引的 API,引擎端调用该 API 即可实现索引构建功能。对于 Spark 3.3 及以上版本,已经提供有索引的 SQL 语句,在 Iceberg 的 Spark 模块实现 Spark 提供的索引接口即可。

  1. 构建索引

我们采用异步构建索引,不影响主线任务。也提供了增量构建索引功能,只对 append 数据进行构建索引。调用 TableScan 读取数据,按照 data file 的 split offset 切分数据,进行构建索引,并保存索引数据和对应的元数据信息。为了避免出现小文件存在,我们会进行索引数据合并。

  1. 索引文件存储

索引文件格式采用[puffin]https://iceberg.apache.org/puffin-spec/格式,这是一种二进制格式。 Magic Blob₁ Blob₂ ... Blobₙ Footer

在 Footer 中保存每个 blob 的元数据信息。索引构建成功后,会生成类似于下面内容的文件。

587a24252f373ef1a6378c2974d3b313.png

索引带来的收益

Range-Encoded BitMap 适用于多维分析场景,且 Ranger 范围较小时,效果非常明显。下面我们基于 Spark 引擎性能测试。

  1. 构造 1TB 的 SSB 测试数据,分别在构建 Index 前后,对以下用例进行测试。

Q1: SELECT count(*) FROM lineorder WHERE  lo_ordtotalprice = 19665277
Q2: SELECT count(*) FROM lineorder WHERE  lo_ordtotalprice = 19665277 AND lo_revenue  = 2141624
Q3: SELECT count(*) FROM lineorder WHERE  lo_ordtotalprice = 19665277 AND lo_revenue  >=10304000
Q4: SELECT count(*) FROM lineorder WHERE  lo_ordtotalprice = 21877827 AND lo_revenue  >= 83800  AND lo_revenue  <= 103800
Q5: SELECT count(*) FROM lineorder WHERE  lo_ordtotalprice > 21877827 AND lo_revenue  >= 83800  AND lo_revenue  <= 93800
Q6: SELECT count(*) FROM lineorder WHERE lo_ordtotalprice >= 93565 AND   lo_ordtotalprice < 93909
Q7: SELECT count(*) FROM lineorder WHERE   lo_ordtotalprice >= 93565 AND   lo_ordtotalprice < 91003562 AND lo_revenue    >=904300 AND lo_revenue    <= 9904300

0835816fb54784c55049da5a7daddc9a.png

左图展示了 7 条 SQL 语句分别在没有 Index 和采用 Index 情况下的执行时间。右图展示采用 Index 后,7 条 SQL 语句读数据的 split 数量。很明显读数据的 split 数量越少,Index 效果越好。最糟糕的情况,所有的 split 都参数计算,这时和没有构建索引的效果类似。

  1. 采用 SSB 基准测试

由于 SSB 提供的测试场景,和 Range-Encoded 有利的场景,不太匹配,所以 Index 的效果并没有明显的效果。但也不会比不采用 Index 的效果差。如下面左图,分别是构建索引前后,SQL 语句的执行时间,构建索引的优势并没有体现出来。右图中,可以看到所有的 split 都参与了计算。

05bc8ae34626246ab123d565a4721b10.png

总结

根据上面的介绍,这里总结下 Iceberg 中索引实现的一些特征:

  • 细粒度索引级别:提供 RowGroup/Stripe 级别的索引,可以更加精确的定位数据的查询范围,减少不必要数据输入,从而提高查询性能;

  • 索引作用于执行端:查询任务被分配多个执行端,每个执行端只判断该节点上的 RowGroup/Stripe 数据是否符合即可;

  • 适配多种引擎:索引构建后,可用于多种引擎;

  • 提供异步构建 Index,从而不影响主业务的进行;

  • 适用于高基数 & 低基数场景,且占有存储空间小。满足范围查询、等值查询等场景。且范围越小,收益效果越明显。

本文提及的 Iceberg 索引功能已在火山引擎 EMR 产品中对外提供服务,欢迎大家试用体验。

b07fdd90758b00cb2052d545b180d362.png 点击「阅读原文」立即体验

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/539298.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

治病如救火,怎样让新药研发更快、更省、更准?

说起医疗与生命科学行业&#xff0c;许多人可能都会想到一句俗语——“治病如救火”&#xff0c;可见其分秒必争的时效性。 然而&#xff0c;如果与日新月异的科技行业相比&#xff0c;医疗与生命科学行业在研发上的速度则慢得惊人。来自《自然》杂志的数据显示&#xff0c;一款…

搭建企业级ESB:让接口管理高效

目 录 01 接口管理现状分析‍‍‍‍‍ 02 ESB对接口的管理‍‍‍‍‍‍ 03 ESB接口管理的发展‍‍‍‍ 04 总结 01 接口管理现状分析‍ 随着社会的发展企业中建立了许多系统&#xff0c;系统中提供了许多接口作为业务解耦的重要手段。随着业务关系越来越复杂、依赖越来越多&…

Krpano之一全景图中嵌入可闪烁的热点图片

效果 步骤 1、打开ptgui软件加载全景图 2、镜头参数设置 3、编辑全景图 4、设置编辑模式 5、拖动鼠标和划动两个方向来调整全景图范围 调整后大概是这样的,我只要在这个区域画一个面即可,尽量让调整后是俯视图,这样在这基础上画的面会比较正一些

拼多多买家如何导出“个人中心”订单信息

经常在拼多多买东西&#xff0c;有时候需要把订单的物流信息导出来&#xff0c;方便记录和统计。现介绍如何使用dumuz工具来实现批量下载拼多多订单。 应用功能描述 模拟人工操作拼多多"个人中心-我的订单”订单网页&#xff0c;批量查询获取拼多多自己买的商品的订单数…

Istio 微服务架构的演变

微服务架构的演变 单体模式下面一个应用通常会有一个app server&#xff0c;这个app server里面会有不同的子模块&#xff0c;每一个模块都写在同一个应用包里面&#xff0c;模块和模块之间的边界有些时候设计的不是特别清晰&#xff0c;特别早期代码混合在一起那么意味着互相的…

PCL学习之滤波算法

前言 点云滤波作为常见的点云处理算法&#xff0c;一般是点云处理的第一步&#xff0c;对后续处理有很重要作用。滤波 有很多方面也有很多种功能&#xff0c;比如去除噪声点、离群点、点云平滑以及空洞、数据压缩等 原始点云数据往往包含大量散列点、孤立点&#xff0c;在获取…

CS 224N总结

CS 224N网址&#xff1a;Stanford CS 224N | Natural Language Processing with Deep Learning Lecture1 PPT网址&#xff1a;PowerPoint Presentation (stanford.edu) 这一讲主要讲了NLP研究的对象&#xff0c;我们如何表示单词的含义&#xff0c;以及Word2Vec方法的基本原…

Ubuntu22 k8s 1.27.1 安装及集群搭建教学(2023.5.16 k8s 最新版本教学,只看这一篇就够了哦!保姆级教程!不行你来找我!)

Ubuntu22 k8s 1.27.1 安装及集群搭建教学&#xff08;2023.5.16 k8s 最新版&#xff0c;只看这一篇就够了哦&#xff01;保姆级教程&#xff01;&#xff01;不行你来找我&#xff01;&#xff09; 温馨提示请仔细阅读&#xff1a;❤️❤️❤️❤️❤️❤️❤️❤️ 1. 由于新版…

Linux系统学习须牢记这几点

工欲善其事须先利其器&#xff0c;想了解Linux技术&#xff0c;先要有一套教学平台,请教同行或者老师来为我们解答&#xff0c;当然也可以下载Cygwin进行学习。但是自主学习的这一过程很困难&#xff0c;因为没有别人的帮助&#xff0c;我们或许会感到迷茫&#xff0c;也会出现…

Spring整合Mybatis、Junit

文章目录 1 Spring整合Mybatis思路分析1.1 环境准备步骤1:准备数据库表步骤2:创建项目导入jar包步骤3:根据表创建模型类步骤4:创建Dao接口步骤5:创建Service接口和实现类步骤6:添加jdbc.properties文件步骤7:添加Mybatis核心配置文件步骤8:编写应用程序步骤9:运行程序 1.2 整合…

STM32F1定时器(TIM1~TIM8)

一、stm32f1定时器简介 1.1、定时器分类 STM32共11个定时器&#xff0c;2个高级控制定时器TIM1和TIM8&#xff0c;4个通用定时器TIM2~TIM5&#xff0c;两个基本定时器TIM6和TIM7&#xff0c;两个看门狗定时器和一个系统滴答定时器Systick. 高级定时器TIM1和TIM8的时钟由APB1产…

想改进婴儿fNIRS数据分析?基于这些先进方法的评估值得一看!

导读 在过去的十年中&#xff0c;fNIRS提供了一种非侵入性的方法来研究发展人群的神经激活。尽管fNIRS在发展认知神经科学中的应用越来越多&#xff0c;但在如何预处理和分析婴儿fNIRS数据方面却缺乏一致性或共识。本研究考察了对婴儿fNIRS数据应用更高级统计分析的可行性&…

智聚北京!相约全球人力资源数智化峰会

人力资源是推动经济社会发展的第一资源。作为我国经济压舱石的中央企业在对标世界一流企业和管理提升方面的持续创新&#xff0c;各行业领军企业围绕组织变革、管理升级、全球化发展走深走实。人力资源管理正从传统职能管理与管控&#xff0c;向紧贴业务战略实现、组织边界和人…

阿里巴巴-1688-退款退货明细下载(导出)

DUMUZ是什么&#xff1f; Dumuz是一款软件产品&#xff0c;可模拟人在电脑上的不同系统之间操作行为&#xff0c; 替代人在电脑前执行具有规律与重复性高的办公流程。 目前基于实际业务场景在软件搭建了模拟实现天猫/淘宝批量订单发货、备注插旗、页面商品数据采集、已买宝贝订…

小米AI实验室多模态图片翻译论文入选自然语言处理领域顶级会议ACL 2023

近日&#xff0c;ACL 2023的论文录用结果公布&#xff0c;小米AI实验室机器翻译团队联合厦门大学苏劲松教授团队在多模态图片翻译方向的最新研究成果已被ACL 2023主会录用&#xff0c;标志着小米在多模态机器翻译方向取得了重要进展。 ACL&#xff08;Annual Meeting of the As…

单片机--实战练习

目录 【1】GPIO 1.定义 2.应用 I - Input - 输入采集 O - Output - 输出控制 ​编辑​编辑 3.GPIO结构框图 4.功能描述 输入功能 输出功能 5.相关寄存器 【2】点亮一盏LED灯 1.实验步骤 2.编程实现 3.编译下载 4.复位上电 练习&#xff1a;实现LED灯闪烁…

Cocos Shader 转场特效合集!卡牌必备,免费开源!

接前两期&#xff0c;孙二喵的 AIGC 卡牌接近尾声了&#xff01;链接&#xff1a; AIGC 制作卡牌1AIGC 制作卡牌2 最近&#xff0c;二喵遇到一个很头疼的问题&#xff01;就是如何实现既流畅、又生动的转场特效。 经过一番大战之后&#xff0c;我实验了多个效果&#xff0c;一共…

记录--vue3优雅的使用element-plus的dialog

这里给大家分享我在网上总结出来的一些知识&#xff0c;希望对大家有所帮助 如何优雅的基于 element-plus,封装一个梦中情 dialog 优点 摆脱繁琐的 visible 的命名&#xff0c;以及反复的重复 dom。 想法 将 dialog 封装成一个函数就能唤起的组件。如下&#xff1a; addDialog(…

Python每日一练(20230518) 螺旋矩阵 I\II\III\IV Spiral Matrix

目录 1. 螺旋矩阵 I Spiral Matrix i &#x1f31f;&#x1f31f; 2. 螺旋矩阵 II Spiral Matrix ii &#x1f31f;&#x1f31f; 3. 螺旋矩阵 III Spiral Matrix iii &#x1f31f;&#x1f31f; 4. 螺旋矩阵 IV Spiral Matrix iv &#x1f31f;&#x1f31f; &#…

探索Vue的组件世界-组件通信

目录 组件跨层级访问 访问外层组件 定向消息 ref&#xff08;父组件访问子组件&#xff09; 依赖注入 依赖注入&#xff0c;vue2.0实现源码 组件封装 组件二次封装 小结 组件跨层级访问 访问外层组件 // 获取 根组件 的数据 this.$root.pri;// 写入 根组件 的数据 t…