升级指南

DataFusion 48.0.0

qianmoQqianmoQ· 更新于 2026-09-29· 阅读 13 分钟· 0 次阅读

登录后可跨设备保存划线和私人笔记登录

升级指南

DataFusion 48.0.0

Expr::Literal 现在带有可选元数据

Expr::Literal 变体现在包含可选元数据,从而能够传递 Arrow 字段元数据,以支持扩展类型及其他用途。

这意味着类似下面这样的代码

match expr {
...
  Expr::Literal(scalar) => ...
...
}

应更新为:

match expr {
...
  Expr::Literal(scalar, _metadata) => ...
...
}

同样,构造 Expr::Literal 也需要元数据。lit 函数没有变化,仍然返回一个不带元数据的 Expr::Literal。

Expr::WindowFunction 现在被 Box 包装

Expr::WindowFunction 现在是 Box<WindowFunction>,而不再是直接的 WindowFunction。做出这一改动是为了减小 Expr 的大小,并提升查询规划时的性能(详见 devlive-community/knowforge#16207 的讨论)。

这是一个破坏性变更,因此如果你直接对 Expr::WindowFunction 进行模式匹配,就需要更新代码。例如,如果你有这样的代码:

match expr {
  Expr::WindowFunction(WindowFunction {
    params:
      WindowFunctionParams {
       partition_by,
       order_by,
      ..
    }
  }) => {
    // Use partition_by and order_by as needed
  }
  _ => {
    // other expr
  }
}

你需要将其改为:

match expr {
  Expr::WindowFunction(window_fun) => {
    let WindowFunction {
      fun,
      params: WindowFunctionParams {
        args,
        partition_by,
        ..
        },
    } = window_fun.as_ref();
    // Use partition_by and order_by as needed
  }
  _ => {
    // other expr
  }
}

SQL 的 VARCHAR 类型现在在 Arrow 中表示为 Utf8View

SQL VARCHAR 类型的映射已从 Utf8 更改为 Utf8View,这提升了许多字符串操作的性能。你可以在 DataFusion 关于德式字符串的博客文章 中了解更多关于 Utf8View 的内容。

这意味着,当你创建一个包含 VARCHAR 列的表时,它现在会使用 Utf8View 作为底层数据类型。例如:

> CREATE TABLE my_table (my_column VARCHAR);
0 row(s) fetched.
Elapsed 0.001 seconds.

> DESCRIBE my_table;
+-------------+-----------+-------------+
| column_name | data_type | is_nullable |
+-------------+-----------+-------------+
| my_column   | Utf8View  | YES         |
+-------------+-----------+-------------+
1 row(s) fetched.
Elapsed 0.000 seconds.

通过修改 datafusion.sql_parser.map_varchar_to_utf8view 配置项,可以恢复使用 Utf8 的旧行为。例如:

> set datafusion.sql_parser.map_varchar_to_utf8view = false;
0 row(s) fetched.
Elapsed 0.001 seconds.

> CREATE TABLE my_table (my_column VARCHAR);
0 row(s) fetched.
Elapsed 0.014 seconds.

> DESCRIBE my_table;
+-------------+-----------+-------------+
| column_name | data_type | is_nullable |
+-------------+-----------+-------------+
| my_column   | Utf8      | YES         |
+-------------+-----------+-------------+
1 row(s) fetched.
Elapsed 0.004 seconds.

ListingOptions 的 collect_stat 默认值由 true 变更为 false

此变更使其与 SessionConfig 的默认值保持一致。大多数用户不会受到这一变更的影响,但如果你直接使用 ListingOptions,并且依赖 collect_stat 默认值为 true,则需要在代码中显式将其设置为 true。

ListingOptions::new(Arc::new(ParquetFormat::default()))
    .with_collect_stat(true)
    // other options

为用户自定义函数处理 FieldRef 而非 DataType

为了支持元数据处理和扩展类型,用户自定义函数现在改为使用以 FieldRef(而非 DataType 和可空性)作为参数的 trait。这样可以为这两个参数提供统一的接口,并且还能访问元数据字段,元数据字段可用于扩展类型。

要升级实现了 ScalarUDFImpl 的结构体,如果你实现了 return_type_from_args,则需要改为实现 return_field_from_args。如果你的函数不需要处理元数据,这只是一次简单的改动——将输出数据重新包装为 FieldRef。你在字段上指定的名称并不重要,规划阶段会将其覆盖。ReturnInfo 已被移除,因此你需要删除所有对它的引用。

ScalarFunctionArgs 现在包含一个名为 arg_fields 的字段。你可以在调用期间使用它来访问与列值相关联的元数据。

要升级用户自定义聚合函数,现在有一个 return_field 函数,它允许你同时指定函数的元数据和可空性。如果你不需要处理元数据,则无需实现该函数。

聚合函数最大的变化在于累加器参数。AccumulatorArgs 和 StateFieldsArgs 现在都包含 FieldRef 而不是 DataType。

要升级窗口函数,ExpressionArgs 现在包含输入字段而非输入数据类型。设置这些字段时,字段的名称并不重要,因为规划阶段会将其覆盖。你只需要将现有的数据类型包装为字段,并根据使用场景设置可空性即可。

物理表达式返回 Field

为了支持用户自定义函数处理元数据的这些变更,PhysicalExpr trait 现在必须根据输入 schema 指定返回 Field。要升级实现了 PhysicalExpr 的结构体,你需要实现 return_field 函数。physical-expr crate 中提供了大量示例。

FileFormat::supports_filters_pushdown 被 FileSource::try_pushdown_filters 取代

为了支持更通用的过滤下推,FileFormat::supports_filters_pushdown 被 FileSource::try_pushdown_filters 取代。如果你实现了使用自定义 FileSource 的自定义 FileFormat,则需要实现 FileSource::try_pushdown_filters。可参考 ParquetSource::try_pushdown_filters 了解实现示例。

FileFormat::supports_filters_pushdown 已被移除。

移除 ParquetExec、AvroExec、CsvExec、JsonExec

ParquetExec、AvroExec、CsvExec 和 JsonExec 在 DataFusion 46 中已被弃用,并在 DataFusion 48 中被移除。这比 API 弃用指南中描述的常规流程要早,因为所有测试都已经覆盖了新的 DataSourceExec,而不是这些旧的结构。随着我们对 DataSource 的不断演进,这些旧结构开始出现"陈旧腐化"的迹象(已经不能正常工作,但由于缺乏测试覆盖而无人察觉)。

在 FileOpener trait 中新增 PartitionedFile 参数

这是正确修复同时涉及分区列和文件列的过滤条件下推(例如 day = username['dob'])所必需的。

如果你实现了自定义的 FileOpener,则需要添加 PartitionedFile 参数,但不要求以任何方式使用它。

评论

登录后参与评论

正在加载评论…