Apache Arrow 的列式内存格式

Apache Arrow 的列式存储格式是一种内存数据组织标准,它通过物理布局、Array(数组)、Schema(模式)和 RecordBatch(记录批次)等,优化了大数据的存储与处理。这种格式以列而非行来存储数据,从而提高了数据访问效率,支持跨平台和多种编程语言,且无需序列化开销,适应现代硬件架构,特别适合于高效的数据分析操作。

01 概述


下图描述了 Apache Arrow 中列式存储格式的主要组成部分,RecordBatch 是 Apache Arrow 中一组具有相同结构的数组 Array 或分块数组 ChunkedArray 构成的集合,它表示一个逻辑上相关联的数据集,例如数据库表的多行记录。Schema 定义了这些数组的组织结构,并且提供了一种方式来描述和管理这些数组的基本属性和附加信息;每个数组或分块数组在 Schema 中都有一个对应的字段 Field,这个字段记录了数组的名称和数据类型 DataType,这些名称和数据类型可以是用户指定的,也可以是从文件中读取得到的;多个这样的字段被组织在一个 Schema 结构中。

(图片来源:https://img-blog.csdnimg.cn/img_convert/01bee720e9eacb5188ccd107e54e4986.png)

Apache Arrow 中自下而上主要的结构说明如下:

  • Physical Layout(物理布局)Physical Layout (或 DataTypeLayout) 定义了数据类型的内存布局,即如何在内存中表示和组织数据。它描述了数据类型的结构、大小和对齐方式,以及如何存储和访问数据的元数据信息。

  • DataType(数据类型)DataType 是 Apache Arrow 中定义数据的类型和属性的对象,是一种逻辑类型 。它描述了数据的基本类型(如整数、浮点数、字符串等),并可以包含其他的元数据信息(如字段名、单位、精度等)。每个 DataType 都与特定的 Physical Layout 关联,以确定数据在内存中的布局和表示方式。

  • Array(数组)Array(或 Vector) 是 Apache Arrow 中的数据容器,用于存储一系列具有相同数据类型的元素。它是在特定 Physical Layout 的基础上创建的,按照特定的内存布局存储数据。Array 提供了对数据的高效访问和操作方法,并支持常见的数组操作,例如索引、切片、过滤等。

  • RecordBatch(记录批)RecordBatch 是 Apache Arrow 中的数据集合,由一组具有相同结构的 Array 组成。它表示一个逻辑上相关联的数据集,例如数据库表的多行记录。RecordBatch 中的每个 Array 代表一个列,而 RecordBatch 中的行数由 Array 的长度确定。RecordBatch 提供了一种高效的方式来处理和传输数据集,支持批处理操作和列式访问模式。

02 物理布局 Physical Layout


Apache Arrow 中的物理布局是其数据组织格式的基础,它决定了数据在内存中的存储方式和组织结构,以实现高效的数据访问、处理和传输。通过优化物理布局,可以提高数据处理的速度和效率,同时支持跨系统和编程语言的数据交换和共享。

物理布局结构体DataTypeLayout的 C++ 实现被定义在cpp\src\arrow\type.h 头文件中,其中定义了 4 种 BufferSpec :FixedWidth(单值定长类型),VariableWidth(变长类型),Bitmap(位图记录空值),AlwaysNull(始终为空)

结构体DataTypeLayout还包含一个 BufferSpec 对象数组的 buffers成员,用于存储每个预期缓冲区的布局规范;has_dictionary成员表示该类型是否期望有一个关联的字典数组;variadic_spec成员是一个可选的BufferSpec 对象,用于指定超出 buffers 大小下限的缓冲区的规范

cpp 复制代码
struct ARROW_EXPORT DataTypeLayout {
  enum BufferKind { FIXED_WIDTH, VARIABLE_WIDTH, BITMAP, ALWAYS_NULL };

  /// Layout specification for a single data type buffer
  struct BufferSpec {
    BufferKind kind;
    int64_t byte_width;  // For FIXED_WIDTH

    bool operator==(const BufferSpec& other) const {
      return kind == other.kind &&
             (kind != FIXED_WIDTH || byte_width == other.byte_width);
    }
    bool operator!=(const BufferSpec& other) const { return !(*this == other); }
  };

  static BufferSpec FixedWidth(int64_t w) { return BufferSpec{FIXED_WIDTH, w}; }
  static BufferSpec VariableWidth() { return BufferSpec{VARIABLE_WIDTH, -1}; }
  static BufferSpec Bitmap() { return BufferSpec{BITMAP, -1}; }
  static BufferSpec AlwaysNull() { return BufferSpec{ALWAYS_NULL, -1}; }

  /// A vector of buffer layout specifications, one for each expected buffer
  std::vector<BufferSpec> buffers;
  /// Whether this type expects an associated dictionary array.
  bool has_dictionary = false;
  /// If this is provided, the number of buffers expected is only lower-bounded by
  /// buffers.size(). Buffers beyond this lower bound are expected to conform to
  /// variadic_spec.
  std::optional<BufferSpec> variadic_spec;

  explicit DataTypeLayout(std::vector<BufferSpec> buffers,
                          std::optional<BufferSpec> variadic_spec = {})
      : buffers(std::move(buffers)), variadic_spec(variadic_spec) {}
};

基于DataTypeLayout结构体中的 4 种 BufferSpec 进行组合使用,Apache Arrow 提供了多种物理布局类型如下表所示:

Layout Type Buffer 0 Buffer 1 Buffer 2 Variadic Buffers
Primitive validity data
Variable Binary validity offsets data
Variable Binary View validity views data
List validity offsets
List View validity offsets sizes
Fixed-size List validity
Struct validity
Sparse Union type ids
Dense Union type ids offsets
Null
Dictionary-encoded validity data (indices)
Run-end encoded
  • 固定大小的原始类型(Primitive (fixed-size)):具有相同字节或位宽的值序列
  • 可变大小的二进制类型(Variable-size Binary):具有可变字节长度的值序列,支持使用 32 位和 64 位长度编码的两种变体
  • 可变大小二进制的视图(View of Variable-size Binary):具有可变字节长度的值序列,与可变大小二进制不同,这种布局的值分布在可能多个缓冲区中,而不是密集且顺序地打包在单个缓冲区中
  • 可变大小的列表(Variable-size List):一种嵌套布局,其中每个值是来自子数据类型的可变长度值序列,支持使用 32 位和 64 位长度编码的两种变体
  • 可变大小列表的视图(View of Variable-size List):一种嵌套布局,其中每个值是来自子数据类型的可变长度值序列;这种布局与可变大小列表不同,它有一个额外的缓冲区包含每个列表值的大小。这消除了偏移量缓冲区必须有序的限制
  • 固定大小的列表(Fixed-size List):一种嵌套布局,其中每个值具有相同数量的元素,来自子数据类型 child array
  • 结构体(Struct):由具有相同长度但可能不同类型命名子字段的集合组成的嵌套布局
  • 稀疏和密集联合(Sparse and Dense Union):一种嵌套布局,表示一系列值的序列,每个值的类型都可以从一系列子数组类型中选择
  • 空值(Null):一系列全部为 null 的值序列
  • 字典编码(Dictionary-Encoded):由整数序列组成的布局(任何位宽),这些整数代表索引到可能为任何类型的字典中
  • 运行结束编码(Run-End Encoded, REE):由两个子数组组成的嵌套布局,一个表示值,一个表示相应值运行结束的逻辑索引

03 数据类型 DataType


基于物理布局 physical layout,Arrow 提供了一套对应的逻辑类型 logical type,即 DataType

根据物理布局中的定长类型(Fixed-size)和变长类型(Variable-size)等类型划分,Arrow 提供了如下种类的数据类型:

  • 定长类型(FixedWidthType):Boolean, Int, Floating Point, Decimal, Date, Time, Timestamp, Interval, Duration
  • 嵌套类型(Nested Types):List, Struct, Map, Union

这些类型的 C++ 实现被定义在cpp\src\arrow\type.h 头文件中,类型之间的派生关系如下(参考原文:Apache arrow 极致模块化、可组合的数据平台-CSDN博客

cpp 复制代码
/*
 * ListType  LargeListType FixedListType
 *    │             │            │
 *    │             ▼            │
 *    └───────► BaseListType◄────┘     StructType          UnionType         RunEndEncodedType
 *                     │                   │                   │                   │
 *                     │                   │                   │                   │
 *                     └───────────────────┴───►NestedType◄────┴───────────────────┘            ExtensionType
 *                                                   │                                               │
 *                                                   │                                               │
 *                                                   └──────────────► DataType ◄─────────────────────┘
 *                                                                      ▲
 *                                                                      │
 *                   ┌────────────────┬──────────────────────┬────►FixedWidthType ◄───┬─────────────────────┬─────────────────┐
 *                   │                │                      │                        │                     │                 │
 *                   │                │                      │                        │                     │                 │
 *                   │                │                      │                        │                     │                 │
 *           DictionaryType   PrimitiveType           ┌─►NumberType◄──┐           TemporaType     FixedSizeBinaryType   BaseBinaryType
 *                                                    │               │                ▲                    ▲            ▲         ▲
 *                                                    │               │                │                    │            │         │
 *                                                IntegerType FloatingPointType   ┌─►DateType◄──┐      DecimalType  StringType  LargeStringType
 *                                                                                │             │         ▲      ▲
 *                                                                                │             │         │      │
 *                                                                             Date32Type  Date64Type 128Type, 256Type
 */

Arrow 提供的数据类型详细如下表:(参考原文:Arrow Columnar Format --- Apache Arrow v18.0.0.dev61

Type Type Parameters Physical Layout
Null Null
Boolean Fixed-size Primitive
Int - bit width - signedness
Floating Point - precision
Decimal - bit width - scale - precision
Date - unit
Time - bit width - unit
Timestamp - unit - timezone
Interval - unit
Duration - unit
Fixed-Size Binary - byte width Fixed-size Binary
Binary Variable-size Binary with 32-bit offsets
Utf8
Large Binary Variable-size Binary with 64-bit offsets
Large Utf8
Binary View Variable-size Binary View
Utf8 View
Fixed-Size List - value type - list size Fixed-size List
List - value type Variable-size List with 32-bit offsets
Large List - value type Variable-size List with 64-bit offsets
List View - value type Variable-size List View with 32-bit offsets and sizes
Large List View - value type Variable-size List View with 64-bit offsets and sizes
Struct - children Struct
Map - children - keys sortedness Variable-size List of Structs
Union - children - mode - type ids Dense or Sparse Union
Dictionary - index type - value type - orderedness Dictionary Encoded
Run-End Encoded - run end type - value type Run-End Encoded

04 数组 Array


Array 数据结构被定义为 ArrayData 包括如下主要属性:

  • type (DataType):指向 DataType 类型的共享指针,表示数组的数据类型
  • length (int64_t):表示数组的长度
  • null_count (int64_t):可变的 atomic<int64_t>类型,表示数组的空值计数
  • offset (int64_t):表示逻辑上进入物理缓冲区 Buffer 的起始点
  • buffers (vector<Buffer>):存储 Buffer 类型共享指针的向量,表示数组的缓冲区
  • child_data (vector<ArrayData>):存储 ArrayData 类型共享指针的向量,表示数组的子数组
  • dictionary (ArrayData):指向 ArrayData 类型的共享指针,表示数组的字典,仅用于字典类型
cpp 复制代码
struct ARROW_EXPORT ArrayData {
  // ...
  std::shared_ptr<DataType> type;
  int64_t length = 0;
  mutable std::atomic<int64_t> null_count{0};
  // The logical start point into the physical buffers (in values, not bytes).
  // Note that, for child data, this must be *added* to the child data's own offset.
  int64_t offset = 0;
  std::vector<std::shared_ptr<Buffer>> buffers;
  std::vector<std::shared_ptr<ArrayData>> child_data;

  // The dictionary for this Array, if any. Only used for dictionary type
  std::shared_ptr<ArrayData> dictionary;
};

不同数据类型的 Array 的物理布局也不一样,下面结合实例介绍几种常用物理布局类型的 Array 数组的数据组织方式(原文参考:《In-Memory Analytics with Apache Arrow》,本节相关图片也来源于此)

4.1 Fixed-size Primitive Layout

Primitive 类型的数组表示一个值数组,每个值具有相同的物理插槽(physical slot)宽度(固定长度数据类型的所占内存空间大小),通常以字节为单位

例如:一个Int32类型的数组 [1, null, 2, 4, 8],则该数组的 length = 5; null_count = 1

该数组的 buffers中包含两个 Buffer:

  • Validity Bitmap Buffer:与数组中值有效性相关联的位图,该 Bitmap 的内存空间是被连续分配,但是不需要和Value Buffer在内存空间中相邻
  • Value Buffer:一个连续的内存缓冲区用于保存数组的值,其总大小至少与插槽宽度乘以数组长度一样大

Int32类型数组例子的物理布局如下图所示:

4.2 Variable-size Binary Layout

Variable-size Binary Layout 是用于存储可变大小二进制数据类型的布局方式,可变大小二进制数据类型通常用于表示字符串、变长字节数组等可变长度的二进制数据

例如:一个字符串类型的数组 ['Water', 'Rising'],则该数组的 length = 2; null_count = 0

该数组的 buffers中包含三个 Buffer:

  • Validity Bitmap Buffer:与数组中值有效性相关联的位图,该 Bitmap 的内存空间是被连续分配,但是不需要和Value Buffer在内存空间中相邻
  • Offsets Buffer:偏移量缓冲区是一个整数数组,用于存储每个元素的起始偏移量;偏移量表示了每个元素在数据缓冲区中的起始位置,通过偏移量,可以快速定位和访问每个元素的数据;Offsets Buffer的偏移量通常从 0开始以Value Buffer的实际长度值为结束,例如本例子中偏移量缓冲区的值为 [0, 5, 11]分别对应了元素值 Water的起始位置 0 和元素值 Rising的起始位置 5,以及Value Buffer的实际长度 11
  • Value Buffer:数据缓冲区是一个字节数组,用于存储实际的二进制数据;数据缓冲区包含了所有元素的二进制数据,通过偏移量缓冲区中的偏移量,可以确定每个元素在数据缓冲区中的位置

字符串类型数组例子的物理布局如下图所示:

4.3 Variable-size List Layout

List 是一种嵌套类型,其中每个值是来自子数据类型的可变长度值序列,在语义上类似于上面介绍的可变大小二进制数据类型 Variable-size Binary

例如:一个Int8类型的 List 数组 [[12, -7, 25], null, [0, -127, 127, 50], []],则该数组的 length = 4; null_count = 1

该数组的 buffers中包含两个 Buffer:

  • Validity Bitmap Buffer:与数组中值有效性相关联的位图,该 Bitmap 的内存空间是被连续分配
  • Offsets Buffer:偏移量缓冲区和 Variable-size Binary 布局类型一样是一个整数数组,用于存储每个元素的起始偏移量;与前者不同的是其偏移量表示的是子数组(Child Array)中的数据缓冲区,而不是引用一个额外的数据缓冲区;例如本例子中偏移量缓冲区的值为 [0, 3, 3, 7, 7]分别对应了第一个数组[12, -7, 25]的起始位置 0 ,第二个 NULL 值元素和第三个数组[0, -127, 127, 50]起始位置 3,第四个空数组[]的起始位置 7,以及子数组Value Buffer的实际长度 7

该数组的数据放在嵌套结构child_data中,其 Child Array 是一个Primitive Int8类型的数组,该数组的 length = 7; null_count = 0,包含不使用的 Validity Bitmap Buffer和存储实际数据值的Value Buffer两个缓冲区,其中上层的 Offsets Buffer中的偏移量与 Child Array 中的 Value Buffer 对应

4.4 Fixed-Size List Layout

FixedSizeList 是一种嵌套布局,其每个数组槽都包含一个固定大小的值序列,这些值都具有相同的数据类型

例如:一个Int8类型固定长度为 2 的 FixedSizeList 数组 [[10, null], null, [0, 5]],则该数组的 length = 3; null_count = 1

该数组的 buffers中仅包含一个Validity Bitmap Buffer表示与数组中值有效性相关联的位图,该 Bitmap 的内存空间是被连续分配

该数组的数据放在嵌套结构child_data中,其 Child Array 是一个Primitive Int8类型的数组,该数组的 length = 6; null_count = 3,包含表示子数组中数据有效性的 Validity Bitmap Buffer和存储实际数据值的Value Buffer两个缓冲区

4.5 Struct Layout

Struct 是一种嵌套类型,它通常由多个字段(Field)组成,所以 Struct Layout 通常是具有相同长度但可能不同类型命名子字段的集合组成的嵌套布局

例如:包含两个属性的Struct<name: VarBinary, age: Int32>结构体类型数组 [{'joe', 1}, {null, 2}, null, {'mark', 4}],则该数组的 length = 4; null_count = 1

该数组的 buffers中仅包含一个Validity Bitmap Buffer表示与数组中值有效性相关联的位图,该 Bitmap 的内存空间是被连续分配

这种类型的物理布局中,一个 Struct 数组的每个字段都有一个对应的子数组 Child Array,在本例中 Struct 的 name 和 age 两个字段的数据分别被存储在嵌套结构child_data的两个 Child Array:Field-0 和 Field-1 中

  • Field-0 是一个 Variable-size Binary Layout 物理布局的 String类型数组,其值为 ['joe', null, null, 'mark'],该子数组的 length = 4; null_count = 2,buffers 中包含Validity Bitmap Buffer, Offsets BufferValue Buffer三个缓冲区
  • Field-1 是一个 Fixed-size Primitive Layout 物理布局的 Int32类型数组,其值为 [1, 2, null, 4],该子数组的 length = 4; null_count = 1,buffers 中包含Validity Bitmap BufferValue Buffer两个缓冲区

4.6 Union Layout

Union 是一种可以让同一数组中存储不同数据类型数据值的嵌套类型,它由有序的类型序列定义,Union 类型的数组中每一个物理插槽都是从这些类型中选择一个值;与其他数据类型不同,Union Layout 没有自己的有效性位图,其每个槽的空值由其按数据类型划分的子数组各自确定

针对不同的应用场景,Arrow 中提供了 Dense 和 Sparse 两种不同的 Union Layout,其中 Dense 使用了一个额外的类型标签缓冲区 Types Buffer 和一个偏移量数组 Offsets Buffer 来存储每个值的类型信息和偏移量信息;而 Sparse 则仅使用了一个额外的类型标签缓冲区 Types Buffer 来存储每个值的类型信息;数组实际的数据值被按数据类型划分存储在不同的子数组 Child Array 中

例如:包含两个数据类型的Union<f: Float, i: Int32>联合类型数组 [{f=1.2}, null, {f=3.4}, {i=5}],则该数组的 length = 4; null_count = 0

如果该数组使用 Dense Union Layout 物理布局方式,则该数组的 buffers 字段包含一个额外的类型标签缓冲区 Types Buffer 和一个偏移量数组 Offsets Buffer 来存储每个值的类型信息和偏移量信息的两个缓冲区;该数组实际的数据值被按数据类型划分采用 Fixed-size Primitive Layout 布局方式的 Float 和 Int32 两个子数组 Child Array 各自存储,其物理布局如下图所示:

如果该数组使用 Sparse Union Layout 物理布局方式,则该数组的 buffers 字段仅包含一个存储每个值类型信息的类型标签缓冲区 Types Buffer;该数组实际的数据值同样被按数据类型划分采用 Fixed-size Primitive Layout 布局方式的 Float 和 Int32 两个子数组 Child Array 各自存储,其物理布局如下图所示:

4.7 Dictionary-encoded Layout

Dictionary-encoded Layout 是用于存储字典编码数据类型的布局方式,任何数组都可以进行字典编码,当字段进行字典编码时,值由表示字典中值索引的非负整数数组表示;字典编码数组的内存布局与Primitive Int布局的内存布局相同,字典作为具有自身相应布局的单独列式数组处理。

例如:一个 String 类型字典编码数组 ['foo', 'bar', 'foo', 'bar', null, 'baz'],则该数组的 length = 6; null_count = 1

该数组的 buffers 与Primitive Int布局一致包含两个 Buffer:

  • Validity Bitmap Buffer:与数组中值有效性相关联的位图,该 Bitmap 的内存空间是被连续分配
  • Value Buffer:一个连续的内存缓冲区用于保存字典中值的索引,其总大小至少与插槽宽度乘以数组长度一样大

当数组使用字典编码时,使用dictionary属性中的子数组 Dictionary Array 来保存压缩的数据值。例如本例中 Dictionary Array 是一个 Variable-size Binary Layout 物理布局的 String 类型数组,该数组的 length = 3; null_count = 0,buffers 包含不使用的 Validity Bitmap Buffer,保存数据值偏移量的Offsets Buffer和存储实际数据值的Value Buffer三个缓冲区

05 数据集合 RecordBatch


在 Apache Arrow 的列式格式中,RecordBatch 是序列化数据的基本单位,如下图所示,它由多个字段(Field)组成的有序集合构成,每个字段对应一个数组,而每个数组的长度彼此相同,但数据类型可能不同

每个字段 Field 代表了数据集中的一个列,它包含了该列的数据以及元数据信息,其中数据即为对应格式的 Array,数组 Array 中存储对应数据类型的单值 Scalar;每个字段 Field 都包含字段名称和字段的数据类型(DataType),这些字段的名称和类型共同构成了 RecordBatch 的模式 Schema

Schema 定义了 RecordBatch 中每个字段的名称、数据类型和其他属性,是数据集结构的元数据描述(RecordBatch 和 Schema 之间的关系可以类比为数据库中的表和表结构的关系;RecordBatch 就像是表中的部分数据,而 Schema 则是表的结构定义,包含了表中每个列的信息)


(图片来源:https://blog.djnavarro.net/posts/2022-11-30_unpacking-arrow-datasets/img/record_batch.png)

Arrow 使用 RecordBatch 将 record/row-oriented 的数据转换为 column-oriented 的列格式,在流数据 Data Stream 中 RecordBatch 消息按照 Schema 后面跟一个或多个 RecordBatch 的方式传输数据如下图所示

其中 RecordBatch 消息包含与由 Schema 确定的物理内存布局相对应的实际数据缓冲区 Buffer,每个 RecordBatch 消息的元数据提供了每个缓冲区的位置和大小,允许直接使用指针重建 Array 数据结构,因此无需进行内存复制

RecordBatch 的序列化形式如上图所示,包括 data headerbody两个部分:

  • data header:RecordBatch 消息的元数据,包括每个扁平化(Flattened)字段 Field 的长度和空计数,Body 中每个组成 Buffer 的内存偏移量和长度等信息
cpp 复制代码
/// A data header describing the shared memory layout of a recordbatch. 
table RecordBatch {
  length: long;                 // number of records
  nodes: [FieldNode];           // Nodes correspond to the pre-ordered flattened logical schema
  buffers: [Buffer];            // Buffers correspond to the pre-ordered flattened buffer tree
  compression: BodyCompression; // Optional compression of the message body
  variadicBufferCounts: [long]; // some types use a variable number of buffers
}
  • body:一个扁平的内存缓冲区序列,以端到端的方式写入,并进行适当的填充以确保至少 8 字节对齐

根据 RecordBatch 消息格式,我们可以得出上述例子的序列化形式,首先其 Schema strs: string ints: Int32 dbls: Float64对应的扁平化形式为

cpp 复制代码
FieldNode 0: String name='strs'
FieldNode 1: Int32 name='ints'
FieldNode 2: Float64 name='dbls'

其对应的 buffers 的序列化形式如下,Flatbuffers 值描述了内存片段的位置和大小

cpp 复制代码
buffer 0: field 0 validity
buffer 1: field 0 offsets
buffer 2: field 0 data
buffer 3: field 1 validity
buffer 4: field 1 data
buffer 5: field 2 validity
buffer 6: field 2 data

对于某些类型(如 Utf8View)使用可变数量的缓冲区variadicBufferCounts表示,那些预先排序的扁平化逻辑 Schema 中的每个此类字段,variadicBufferCounts 中将有一个条目,指示当前 RecordBatch 中属于该字段的可变参数缓冲区的数量

例如,如下 Schema,有两个具有可变参数缓冲区的字段 BinaryViewUtf8View

c 复制代码
col1: Struct<a: Int32, b: BinaryView, c: Float64>
col2: Utf8View

则 variadicBufferCounts 在每个 RecordBatch 中将有两个条目,对于具有 variadicBufferCounts = [3, 2] 的此模式的 RecordBatch,其扁平化缓冲区为

c 复制代码
buffer 0:  col1    validity
buffer 1:  col1.a  validity
buffer 2:  col1.a  values
buffer 3:  col1.b  validity
buffer 4:  col1.b  views
buffer 5:  col1.b  data
buffer 6:  col1.b  data
buffer 7:  col1.b  data
buffer 8:  col1.c  validity
buffer 9:  col1.c  values
buffer 10: col2    validity
buffer 11: col2    views
buffer 12: col2    data
buffer 13: col2    data

如果文章对你有帮助,欢迎 点赞收藏 👍 ⭐️ 💬,如果还能够 点击关注,那真的是对我最大的鼓励 🔥 🔥 🔥


参考资料

Arrow Columnar Format --- Apache Arrow v18.0.0.dev61

In-Memory Analytics with Apache Arrow (豆瓣) (douban.com)

Apache arrow 极致模块化、可组合的数据平台-CSDN博客

箭头列式格式 --- Apache Arrow v16.1.0 - Arrow 中文

Arrays and tables in Arrow -- Notes from a data witch (djnavarro.net)

Unpacking Arrow Datasets -- Notes from a data witch (djnavarro.net)

相关推荐
十叶知秋14 分钟前
【jmeter】jmeter的线程组功能的详细介绍
数据库·jmeter·性能测试
ycsdn1029 分钟前
Caused by: org.apache.flink.api.common.io.ParseException: Row too short:
大数据·flink
DolphinScheduler社区2 小时前
Apache DolphinScheduler + OceanBase,搭建分布式大数据调度平台的实践
大数据
瓜牛_gn2 小时前
mysql特性
数据库·mysql
时差9533 小时前
MapReduce 的 Shuffle 过程
大数据·mapreduce
奶糖趣多多3 小时前
Redis知识点
数据库·redis·缓存
kakwooi4 小时前
Hadoop---MapReduce(3)
大数据·hadoop·mapreduce
数新网络4 小时前
《深入浅出Apache Spark》系列②:Spark SQL原理精髓全解析
大数据·sql·spark
CoderIsArt4 小时前
Redis的三种模式:主从模式,哨兵与集群模式
数据库·redis·缓存
师太,答应老衲吧6 小时前
SQL实战训练之,力扣:2020. 无流量的帐户数(递归)
数据库·sql·leetcode