从一到无穷大 #8 Arrow,Parquet and ORC

news2024/11/24 22:42:19

文章目录

  • 引言
  • Arrow
  • Parquet
    • Nested Encoding
      • Repetition Levels
      • Definition Levels
    • 列化
    • 压缩
  • ORC

引言

以我的机器为例来做一个简单的计算:

  1. 执行cat /proc/cpuinfo |grep MHz|uniq可以看到目前机器中CPU频率,得到值 2494.140MHZ~=2494140000HZ,即每秒可以执行25亿个脉冲信号,换句话说每一个脉冲信号仅仅用时0.4ns(时钟周期),假设每个脉冲信号为一次CPU计算指令(当然实际不能简单对应,实际的CPU性能还是应该看IPC(Instructions Per Cycle))
  2. 执行getconf LONG_BIT获取CPU的位数,执行lshw -C cpu|grep width获取数据总线宽度,没什么问题的话这里就是64,即CPU每秒可以计算2494.140MHZ*64bit~=18GB/s
  3. 接下来计算内存带宽[21],公式为:内存带宽(GB/s)= 内存总线宽度(bits)/ 8 × 内存频率(MHz)× Number of data transfers per clock = 2) 执行dmidecode -t memory,内存总线宽度为64 bits;内存频率为2933 MT/s~=1466MHZ;类型为: DDR4;所以得出结论内存带宽=21GB/S=1466*000000*8*2/1024/1024/1024
  4. 网卡带宽:执行ip a检查网卡数量;执行ethtool eth0|grep Speed检查网卡带宽,得到10000Mb/s,假设每个TCP包全部装满MTU,即数据包1538字节,包头84字节,实际payload带宽为1.1GB/s
  5. 磁盘带宽:hdparm -t,数据保密。

基于此结果可以推测在纯内存计算中,瓶颈其实在CPU计算中,数据从内存传输到CPU到数据是大于CPU可计算的值的,此时最重要的事情是加速计算(节省计算)。

不同介质导致的瓶颈使得数据存储格式的决策有很大的优化空间,主内存列存储和磁盘列存储之间存在根本差异。CPU列存储倾向于加速计算效率,节省CPU使用量;而磁盘列存储更注重压缩决策,对于存储在磁盘上的数据和网络传输的数据,从磁盘带宽/网络带宽是瓶颈,此时压缩大概率是一个很好的决定,因为原本CPU的资源就是充足的,数据总大小减小会使得整体效率更高。当然高额的压缩率也会利好于存储成本。

回到文章题目。我们简单了解下Arrow,Parquet,ORC代表三种高效的数据存储格式,后两种用于磁盘存储/网络传输,而Arrow用于内存计算。

Arrow

在这里插入图片描述
Arrow的定位在官网首页写的明明白白:

  1. 作为内存列存格式标准,旨在直接和高效地用于计算目的
  2. 提供多语言适配的工具集,作为开发平台
  3. 建立Arrow生态系统

arrow优势可以在[7]中找到相关描述:

  • Data adjacency for sequential access (scans)
  • O(1) (constant-time) random access
  • SIMD and vectorization-friendly
  • Relocatable without “pointer swizzling”, allowing for true zero-copy access in shared memory
  • For simple streaming and file-based serialization, we define a “encapsulated” message format for interprocess communication. Such messages can be “deserialized” into in-memory Arrow array objects by examining only the message metadata without any need to copy or move any of the actual data.

其中最吸引我的地方在于可以从网络包中直接零拷贝的拿到原始数据并构建内存数据结构[22],这归功于Arrow定义的网络传输格式,这在带宽与CPU处理速度差别不大时可以大幅度提升内存处理效率

Arrow也使用到了FlatBuffers作为传输格式中元信息的存储方式[24、25]。

在数据格式方面Arrow依旧和Parquet一样支持多类型嵌套数据结构,并定义了一系列基础数据格式的内存排列方式[7]。

官网中有一些常见问题的官方回复[14]。

Parquet

Nested Encoding

层次化编码是可嵌套的列式存储的基石,Parquet实际采用了Dremel[13]中描述的算法作为核心数据存储的方法,在这个问题上我们聚焦于扁平化和编解码。
在这里插入图片描述

对于一个多类型复杂嵌套结构来说想要扁平化。有两个问题要解决

Repetition Levels

首先要解决的问题给定的多个值判断他们到底属于哪些Record,比如在存储Name.Language.Code的过程中,如果只是存储en-usenen-gb,根本无法判断这个值属于哪个Name.Language。为了区分这些出现的情况,需要每个值附加一个Repetition Levels,标识了在此值字段路径中的哪个重复字段上重复出现。这个东西初次看还挺难理解的,我理解的要点是把整个列式嵌套结构看成一颗树,根节点为虚拟节点,根节点下一级别为实际的单个嵌套结构,此时可以发现Repetition Levels其实就是就是和第一个值的最近公共祖先。

注意永远可以看作虚拟节点的层级代表0,Name,Link都是1,Language为2。

此时看起来就清晰很多,我们以Name.Language.Country作为例子,首先第一个Name.Language中第一个有值,第二个为null,值分别为0和2。第二个Name没有值,所以Repetition Levels其实就是自己,即为1,当然因为此时在Name数组,所以就算有值,其实也是1;到了r2中,当Name.Language.Country不存在的时候自然就是0了。

论文中原始描述如下:

Consider field Code in Figure 2. It occurs three times in r1. Occurrences ‘en-us’ and ‘en’ are inside the first Name, while ’en-gb’ is in the third Name. To disambiguate these occurrences, we attach a repetition level to each value. It tells us at what repeated field in the field’s path the value has repeated. The field path Name.Language.Code contains two repeated fields, Name and Language. Hence, the repetition level of Code ranges between 0 and 2; level 0 denotes the start of a new record. Now suppose we are scanning record r1 top down. When we encounter ‘en-us’, we have not seen any repeated fields, i.e., the repetition level is 0. When we see ‘en’, field Language has repeated, so the repetition level is 2. Finally, when we encounter ‘en-gb’, Name has repeated most recently (Language occurred only once after Name), so the repetition level is 1. Thus, the repetition levels of Code values in r1 are 0, 2, 1.

Notice that the second Name in r1 does not contain any Code values. To determine that ‘en-gb’ occurs in the third Name and not in the second, we add a NULL value between ‘en’ and ‘en-gb’ (see Figure 3). Code is a required field in Language, so the fact that it is missing implies that Language is not defined. In general though, determining the level up to which nested records exist requires extra information.

Definition Levels

其次是判断某个field值属于哪一个层级,尤其是对NULL的判断,我使用Name.Language.Country作为例子,因为存在较高层次的值直接为NULL,需要判断到底哪个层级为null,比如Name.Language.Country其实在第一个和第二个Name中都没有值,但是第一个只是不存在Country,但是第二个是不存在Language,那NULL的层级就是不一样的。

论文中使用Links.Backward作为例子,因为第一个Links中不存在Backward,但是又是第一个出现的值,所以存在r=0,d=1

论文中原始描述如下:

Each value of a field with path p, esp. every NULL, has a definition level specifying how many fields in p that could be undefined (because they are optional or repeated) are actually present in the record. To illustrate, observe that r1 has no Backward links. However, field Links is defined (at level 1). To preserve this information, we add a NULL value with definition level 1 to the Links.Backward column.
Similarly, the missing occurrence of Name.Language.Country in r2 carries a definition level 1, while its missing occurrences in r1 have definition levels 2 (inside Name.Language) and 1 (inside Name), respectively.

列化

本质上是如何把一个嵌套结构抽象成多个column,且高效计算Repetition and Definition LevelsDissectRecord会从decoder中分析Repetition and Definition Levels,然后写入对应FieldWriter,这是一个 tree of field writers,其结构与原始schema层次结构相同。
在这里插入图片描述

压缩

前文已经提到,Parquet旨在实现最大的空间效率,以减少磁盘存储空间和网络传输效率,所以可以预想Parquet一定会使用各种激进的压缩策略。目前支持的压缩算法有如下[15]:

  1. UNCOMPRESSED
  2. SNAPPY
  3. GZIP
  4. LZO
  5. BROTLI
  6. LZ4
  7. ZSTD
  8. LZ4_RAW

但是也正因为与Arrow的应用场景不同,这使得网络传输中还是存在序列化/反序列化成本。

ORC

关于ORC和Parquet的使用业界似乎有一致的共识,即ORC在查询,压缩,兼容性方面在大多数情况下优于Parquet,而且支持ACID与Update/Delete操作,甚至于在ORC的官网也有这样的文字:
在这里插入图片描述

但是感觉看了ORC的Optimized Row Columnar和Parquet的Dremel格式后,感觉差异更多的集中在对于不同系统的负载类型和工程实现上,这部分对我一个新人来说没法想明白。具体资料可以参考[16、17、18、19、20]

参考:

  1. Apache Arrow:一种适合异构大数据系统的内存列存数据格式标准
  2. Apache Arrow 内存数据
  3. Apache Arrow vs. Parquet and ORC: Do we really need a third Apache project for columnar data representation?
  4. An analysis of the strengths and weaknesses of Apache Arrow
  5. Dremio blog: The Origin & History of Apache Arrow
  6. Arrow数据格式-Arrow究竟是个啥
  7. Arrow Columnar Format
  8. 再来聊一聊 Parquet 列式存储格式
  9. Apache Parquet列式存储格式介绍
  10. Parquet文件是怎么被写入的-Row Groups,Pages,需要的内存,以及flush操作
  11. The striping and assembly algorithms from the Dremel paper
  12. Apache Parquet设计解读
  13. Dremel: Interactive Analysis of Web-Scale Datasets
  14. Arrow Frequently Asked Questions
  15. Parquet compression definitions
  16. Using Presto in our Big Data Platform on AWS
  17. Even faster: Data at the speed of Presto ORC
  18. LanguageManual ORC
  19. Hive - ORC 文件存储格式详细解析
  20. orc格式和parquet格式对比
  21. https://en.wikipedia.org/wiki/Memory_bandwidth
  22. Arrow Flight RPC
  23. 深入浅出FlatBuffers原理
  24. 深入浅出 FlatBuffers 之 Schema

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

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

相关文章

【算法】——全排列算法讲解

前言: 今天,我给大家讲解的是关于全排列算。我会从三个方面去进行展开: 首先,我会给大家分析关于全排列算法的思想和定义;紧接着通过手动实现出一个全排列代码来带大家见见是怎么实现的;最后我会给出两道题…

ESP32单片机入门篇

目录 一、ESP32单片机的基本概念 1.双核架构 2. Wi-Fi和蓝牙功能 3. 集成多种外设 4. 支持多种操作系统 二、开发环境 1. Arduino IDE 2. ESP-IDF 三、开发语言 四、注意事项 五、代码例程 (1)点亮LED灯 1. 电路图 2. 代码 3. 代码注释 …

【精品】Java-Stream流详解

Java-Stream流详解 如何学会JDK8中的Stream流,用它来提高开发效率?创建不可变的集合(Immutable 不可变的)场景方法 初试 Stream 流Stream 流的思想Stream 流的作用Stream 流的使用步骤Stream 流的中间方法Stream 流的终结方法 如何…

STM32:利用PWM波控制飞盈电调过程和注意事项

STM32:利用PWM波控制电调过程和注意事项 在进行模型控制的过程中,如四旋翼无人机等,需要用到电机,这些电机需要通过电调来控制电机的转速。在电调模块中带有的说明书一般都是利用遥控器进行控制,有些情况需要自己通过…

【自然语言处理】【大模型】CodeGeeX:用于代码生成的多语言预训练模型

CodeGeeX:用于代码生成的多语言预训练模型 《CodeGeeX: A Pre-Trained Model for Code Generation with Multilingual Evaluations on HumanEval-X》 论文地址:https://arxiv.org/pdf/2303.17568.pdf 相关博客 【自然语言处理】【大模型】CodeGeeX&#…

二叉排序树

二叉排序树 文章目录 二叉排序树创建遍历删除完整代码 假如给你一个数列 (7, 3, 10, 12, 5, 1, 9),要求能够高效的完成对数据的查询和添加。 使用数组 数组未排序: 优点:直接在数组尾添加,速度快。 缺点:查找速度慢. 数…

[图形学] 射线和线段之间的最小距离

1 说在前面 本文的主要内容来自于Unity引擎中Spline功能的一个函数,一开始我难以理解这几个向量运算的作用和几何意义,经过一番思考后总结如下: 该段代码实际上更像是两个直线之间寻找最短距离,然后判断该距离对应的点在其中一条…

STM32利用USB的HID与QT上位机通信

之前使用kingst的逻辑分析仪,打开上位机软件,插上带usb的硬件就可以通信,也不需要打开串口什么的,感觉很方便,于是借用一个周末研究下这个技术。本文主要是用于记录自己学习的过程,顺便分享下学习感悟。 首…

大数据周会-本周学习内容总结012

开会时间:2023.05.07 16:00 线下会议 目录 01【es数据同步至mysql】 1.1【在es中插入数据后能够同步到mysql中】 1.2【修改与删除es中的数据】 02【nifi】 2.1【Nifi的单机及分布式集群部署】 2.2【nifi集群,getFile简单使用nifi】 2.3【nifi使用…

如何利用Requestly提升前端开发与测试的效率,让你事半功倍?

痛点 前端测试 在进行前端页面开发或者测试的时候,我们会遇到这一类场景: 在开发阶段,前端想通过调用真实的接口返回响应在开发或者生产阶段需要验证前端页面的一些 异常场景 或者 临界值 时在测试阶段,想直接通过修改接口响应来…

Nuvoton NK-980IOT开发板 u-boot 编译

前言 最近搭建了 Nuvoton NK-980IOT开发板 的开发编译环境,记录一下 u-boot 的 编译流程 Nuvoton NK-980IOT开发板 资源还是比较的丰富的,可以用于 嵌入式Linux 或者 RT-Thread 的学习开发 开发板上电比较的容易,两根 USB 线即可&#xff0…

进程与线程(二)

进程同步、进程互斥 同步亦称直接制约关系,是指为完成某种任务而建立的两个或多个进程,这些进程因为需要在某些位置上协调它们的工作次序而产生的制约关系。进程间的直接制约关系就是源于他们之间的相互合作。 操作系统要提供“进程同步机制”来解决异…

Oracle的学习心得和知识总结(二十四)|Oracle数据库DBMS程序包解密方法及SQL Developer和Unwrapper的安装与使用

目录结构 注:提前言明 本文借鉴了以下博主、书籍或网站的内容,其列表如下: 1、参考书籍:《Oracle Database SQL Language Reference》 2、参考书籍:《PostgreSQL中文手册》 3、EDB Postgres Advanced Server User Gui…

android 隐藏底部虚拟按键

方法一 滑动屏幕 可重新显示出来 protected void hideBottomUIMenu() { //隐藏虚拟按键&#xff0c;并且全屏 if (Build.VERSION.SDK_INT <11 && Build.VERSION.SDK_INT < 19) { // lower api View v this.getWindow().getDecorView(); v.setSyst…

大众软件组织人事地震:传董事会被裁,5000人的CARIAD何去何从?

作者 | 德新 编辑 | 王博 外媒Business Insider近日爆出一则重磅消息&#xff1a;大众汽车集团CEO Oliver Blume&#xff08;奥博穆&#xff09;有意裁掉旗下软件组织CARIAD的整个董事会。其影响的高层包括&#xff0c;CARIAD CEO Dirk Hilgenberg、CTO Lynn Longo&#xff0c;…

influxdb时序型数据库基础

文章目录 什么是InfluxDB时序数据特点常见应该场景时序数据库解决什么问题InfluxDB的优势InfluxDB常用命令 什么是InfluxDB InfluxDB是一个开源的、高性能的时序型数据库&#xff0c;在时序型数据库DB-Engines Ranking上排名第一。 在介绍InfluxDB之前&#xff0c;先来介绍下…

机器学习随记(5)—决策树

手搓决策树&#xff1a;用决策树将其应用于分类蘑菇是可食用还是有毒的任务 温馨提示&#xff1a;下面为不完全代码&#xff0c;只是每个步骤代码的实现&#xff0c;需要完整跑通代码的同学不建议花时间看&#xff1b;适合了解决策树各个流程及代码实现的同学复习使用。 1 数据…

MySQL锁机制

目录 表级锁&行级锁 排他锁&共享锁 InnoDB行级锁 行级锁&#xff08;record lock&#xff09;&#xff1a; 间隙锁&#xff08;gap lock&#xff09;&#xff1a; 意向锁 InnoDB表级锁 MVCC&#xff08;多版本并发控制&#xff09; 已提交读的MVCC&#xff1a…

Linux下的shell

NC反向shell 1、查看shell类型 echo $SHELLchsh -s 需要修改shell的类型cat /etc/shells 查看存在哪些shell 然后反弹对应的shell&#xff08;正向连接&#xff09; //被控制端 nc -lvvp 8989 -e /bin/bash //控制端 nc 192.168.222.146(被控端ip) 8989 2、没有-e参数反…

css链接悬停时滑动的下划线效果

要创建链接悬停时滑动的下划线效果&#xff0c;可以向锚点标记添加伪元素&#xff0c;并使用 CSS 过渡动画来显示它。 先看效果&#xff1a; 在提供的代码中&#xff0c;a::after 选择器创建了一个伪元素&#xff0c;该伪元素位于 a 标记后面。该伪元素具有绿色背景颜色和 1…