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 可以是数据库中的一个组件(大多数数据库都有某种执行引擎),也可以是几乎不 resembling 数据库的某些其他数据处理应用程序中的一个组件。Acero 不关注用户管理、外部通信、隔离、持久性或一致性。此外,Acero 主要关注读取路径,写入实用程序缺乏任何形式的事务支持。

优化器#

Acero 没有 SQL 解析器。它没有查询规划器。它没有任何优化器。Acero 期望获得关于如何操作数据的非常详细和低级的指令,然后它将完全按照描述执行该操作。

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

分布式#

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

Acero 与…#

Arrow Compute#

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

Arrow Datasets#

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 “函数”接受零个或多个数组、批次或表,并生成一个数组、批次或表。此外,函数调用可以与字段引用和文字结合,形成一个表达式(函数调用树),计算模块可以对其进行评估。例如,给定具有列xy的表,计算x + (y * 3)

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::Array或一个arrow::Scalar

核心概念#

ExecNode#

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

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

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

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

  • 表汇节点将数据累积到表中

注意

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

ExecBatch#

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

../../_images/rb_vs_eb.svg

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

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

  • ExecBatch中的列可以是ArrayScalar。当列是Scalar时,这意味着该列在批次中的每一行都具有单个值。ExecBatch还具有描述批次中行数的length属性。因此,另一种查看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#

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

../../_images/decl_vs_ep.svg

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