Acero 概述#

此页面概述了基本的 Acero 概念,并帮助区分 Acero 与 Arrow 代码库中的其他模块。它面向用户、开发人员、潜在贡献者以及希望扩展 Acero(用于研究或商业用途)的人员。此页面假设读者已熟悉核心 Arrow 概念。此页面不期望读者具备任何关系代数方面的现有知识。

什么是 Acero?#

Acero 是一个 C++ 库,可用于分析大型(可能是无限的)数据流。Acero 允许将计算表示为“执行计划”(ExecPlan)。执行计划接受零个或多个输入数据流并发出单个输出数据流。该计划描述了数据在传递过程中将如何转换。例如,一个计划可能

  • 使用公共列合并两个数据流

  • 通过对现有列计算表达式创建其他列

  • 通过将其写入磁盘中的分区布局来使用数据流

A sample execution plan that joins three streams of data and writes to disk

Acero 不是…#

数据科学家的库#

Acero 不打算由数据科学家直接使用。预计最终用户通常会使用某种前端。例如,Pandas、Ibis 或 SQL。Acero 的 API 侧重于功能和可用算法。但是,此类用户可能希望了解有关 Acero 工作原理的更多信息,以便更好地了解其库的后端处理方式。

数据库#

数据库(或 DBMS)通常是一个更广泛的应用程序,并且通常作为独立服务打包。Acero 可以是数据库中的一个组件(大多数数据库都具有一些执行引擎)或可以是其他数据处理应用程序中的一个组件,该应用程序几乎不类似于数据库。Acero 不关心用户管理、外部通信、隔离、持久性或一致性。此外,Acero 主要关注读取路径,并且写入实用程序缺乏任何类型的交易支持。

优化器#

Acero 没有 SQL 解析器。它没有查询计划器。它没有任何类型的优化器。Acero 预计将获得有关如何操作数据的非常详细和低级别的说明,然后它将完全按照描述执行该操作。

创建最佳执行计划非常困难。细微的差别会对性能产生重大影响。我们确实认为优化器很重要,但我们认为它应该独立于 acero 实现,希望通过 Substrait 等标准以可组合的方式实现,以便任何后端都可以利用它。

分布式#

Acero 不提供分布式执行。但是,Acero 旨在可用于分布式查询执行引擎。换句话说,Acero 不会配置和协调工作器,但它确实期望用作工作器。有时,这种区别有点模糊。例如,Acero 源可能是一个能够执行过滤或其他高级分析的智能存储设备。人们可能会认为这是一个分布式计划。关键的区别在于 Acero 没有将逻辑计划转换为分布式执行计划的功能。此步骤需要在其他地方完成。

Acero 与…#

Arrow 计算#

这在与 Arrow C++ 的关系中进行了更详细的描述,但关键区别在于 Acero 处理数据流,而 Arrow Compute 处理所有数据都在内存中的情况。

Arrow 数据集#

Arrow 数据集库提供了一些用于发现、扫描和写入文件集合的基本例程。数据集模块依赖于 Acero。扫描和写入数据集都使用 Acero。扫描节点和写入节点是数据集模块的一部分。这有助于将文件格式和文件系统的复杂性排除在核心 Acero 逻辑之外。

Substrait#

Substrait 是一个建立查询计划标准的项目。Acero 执行查询计划并生成数据。这使得 Acero 成为 Substrait 的使用者。有关 Substrait 功能的更多详细信息,请参阅使用 Acero 与 Substrait

Datafusion/DuckDb/Velox/等#

许多列式数据引擎正在兴起。我们认为这是一件好事,并鼓励像 Substrait 这样的项目帮助根据需要在引擎之间切换。我们通常不鼓励进行比较基准测试,因为它们几乎不可避免地会受工作负载驱动,并且很少能捕捉到苹果与苹果的比较。有关每个优缺点的讨论超出了本指南的范围。

与 Arrow C++ 的关系#

Acero 模块是 Arrow C++ 实现的一部分。它作为单独的模块构建,但它依赖于核心 Arrow 模块,并且不独立存在。Acero 使用并扩展了核心 Arrow 模块和 Arrow 计算内核的功能。

A diagram of layers with core on the left, compute in the middle, and acero on the right

核心 Arrow 库提供了用于缓冲区和数组的容器,这些容器根据 Arrow 列式格式布局。除了少数例外情况外,核心 Arrow 库不会检查或修改缓冲区的内容。例如,将字符串数组从小写字符串转换为大写字符串将不是核心 Arrow 库的一部分,因为这需要检查数组的内容。

计算模块扩展了核心库,并提供了分析和转换数据的功能。计算模块的所有功能都通过函数注册表公开。Arrow“函数”接受零个或多个数组、批次或表,并生成数组、批次或表。此外,函数调用可以与字段引用和文字结合起来,形成一个表达式(函数调用的树),计算模块可以评估该表达式。例如,计算x + (y * 3),给定一个包含列xy的表。

A sample expression tree

Acero 通过为数据流添加计算操作来扩展这些功能。例如,项目节点可以对批次流应用计算表达式。这将创建一个新的批次流,其中表达式的结果作为新列添加。这些节点可以组合成一个图,以形成更复杂的执行计划。这与将函数组合成树以形成复杂表达式的 方式非常相似。

A simple plan that uses compute expressions

注意

Acero 不使用核心 Arrow 库中的arrow::Tablearrow::ChunkedArray容器。这是因为 Acero 对批次流进行操作,因此不需要多批次数据容器。这有助于降低 Acero 的复杂性,并避免从列具有不同块大小的表中可能出现的棘手情况。Acero 通常会使用arrow::Datum,它是核心模块中的一个变体,可以容纳许多不同的类型。在 Acero 中,datum 将始终持有arrow::Arrayarrow::Scalar

核心概念#

ExecNode#

Acero 中最基本的概念是 ExecNode。ExecNode 具有零个或多个输入和零个或一个输出。如果 ExecNode 具有零个输入,我们将其称为源;如果 ExecNode 没有输出,则我们将其称为接收器。有许多不同类型的节点,每个节点都以不同的方式转换其输入。例如

  • 扫描节点是从文件中读取数据的源节点

  • 聚合节点累积数据批次以计算汇总统计信息

  • 过滤器节点根据过滤器表达式从数据中删除行

  • 表接收器节点将数据累积到表中

注意

可用计算模块的完整列表包含在用户指南

ExecBatch#

数据批次由 ExecBatch 类表示。ExecBatch 是一个二维结构,与 RecordBatch 非常相似。它可以有零个或多个列,并且所有列都必须具有相同的长度。ExecBatch 有几个关键区别

../../_images/rb_vs_eb.svg

记录批次和执行批次都对数组和缓冲区拥有强大的所有权#

  • ExecBatch 没有架构。这是因为ExecBatch 假定是批次流的一部分,并且该流假定具有一致的架构。因此,ExecBatch 的架构通常存储在 ExecNode 中。

  • ExecBatch 中的列要么是Array,要么是Scalar。当列为Scalar时,这意味着该列对于批次中的每一行都有一个值。ExecBatch 还具有一个长度属性,该属性描述了批次中有多少行。因此,查看Scalar 的另一种方法是具有length个元素的常量数组。

  • ExecBatch 包含执行计划使用的其他信息。例如,index 可用于描述批次在有序流中的位置。我们预计ExecBatch 也将发展为包含其他字段,例如选择向量。

../../_images/scalar_vs_array.svg

有四种不同的方法可以使用数组和标量的不同组合来表示给定的数据批次。所有四个执行批次都应被视为语义上等效的。#

从记录批次转换为执行批次始终为零复制。RecordBatch 和 ExecBatch 都引用完全相同的底层数组。仅当执行批次中没有标量时,从执行批次转换为记录批次才为零复制。

注意

Acero 和计算模块都具有批次和数组的“轻量级”版本。在计算模块中,这些被称为BatchSpanArraySpanBufferSpan。在 Acero 中,该概念称为KeyColumnArray。这些类型是同时开发的,并且具有相同的目的。它们旨在提供一个数组容器,该容器可以完全堆栈分配(前提是数据类型是非嵌套的),以避免堆分配开销。理想情况下,这两个概念将在将来合并。

ExecPlan#

ExecPlan 表示一个 ExecNode 对象的图。有效的 ExecPlan 必须至少有一个源节点,但从技术上讲它不需要有汇聚节点。ExecPlan 包含所有节点共享的资源,并具有用于控制节点执行启动和停止的实用程序函数。ExecPlan 和 ExecNode 都与单个执行的生命周期绑定。它们具有状态,并且不期望可重启。

警告

Acero 中的结构,包括 ExecBatch,仍处于实验阶段。 ExecBatch 类不应在 Acero 之外使用。相反,应将 ExecBatch 转换为更标准的结构,例如 RecordBatch

类似地,ExecPlan 是一个内部概念。创建计划的用户应该使用 Declaration 对象。用于使用和执行计划的 API 应该抽象掉底层计划的细节,而不公开对象本身。

声明#

Declaration 是 ExecNode 的蓝图。Declaration 可以组合成一个图,形成 ExecPlan 的蓝图。Declaration 描述了需要完成的计算,但实际上并不负责执行计算。这样,Declaration 就类似于表达式。预计 Declaration 将需要在各种查询表示(例如 Substrait)之间进行转换。Declaration 对象是公共 API,结合 DeclarationToXyz 方法,是 Acero 当前的公共 API。

../../_images/decl_vs_ep.svg

声明是用于实例化执行计划实例的蓝图#