- 大数据
- 数据分析
- 后端
【免费下载链接】datafusion
Apache DataFusion SQL Query Engine
Apache DataFusion 在 2023 年 8 月发布的 29.0.0 版本,是一次包含多项破坏性变更(Breaking Changes)与重要功能增强的里程碑式发布。本文以 dev/changelog/29.0.0.md 记录为主线,结合当前仓库源码逐一拆解 UDAF 创建接口调整、数组/列表访问表达式重构、Arrow 45.0.0 升级与 Decimal 除法语义变更、线性回归聚合函数、sqllogictests 测试框架落地等核心内容,帮助你评估升级影响并快速上手新特性。
版本概览
29.0.0 发布于 2023-08-11,是继 28.0.0 之后的一次大版本更新,主要包括:
- 4 项 Breaking Changes:涉及 UDAF 创建接口、数组函数命名、字段/列表访问表达式 API、Arrow 版本与 Decimal 除法语义;
- 5 项增强特性:SQL 数组替换/删除函数、数组包含运算符
@>/<@、sqllogictests 测试 crate、datafusion-cli多语句支持、线性回归聚合函数; - 一批 Bug 修复:如
interval - timestamp运算禁用、Projection 列名查找、filter 谓词 panic、count(*)别名等; - 大量底层重构:排序保持算子(sort-preserving)相关配置、HashJoin 顺序修复、
ExecutionPlan访问器抽取、内存记账(memory accounting)完善等。
Breaking Changes 详解
1.create_udaf参数签名变更:从单类型到类型向量
本版本将create_udaf函数的input_type参数由DataType改为Vec<DataType>(PR #7096)。这一变更直接影响所有使用datafusion_expr编写自定义聚合函数(UDAF)的开发者。
当前仓库中的实际定义位于 datafusion/expr/src/expr_fn.rs:
pub fn create_udaf( name: &str, input_type: Vec<DataType>, // 由单个 DataType 改为 Vec<DataType> return_type: Arc<DataType>, volatility: Volatility, accumulator: AccumulatorFactoryFunction, state_type: Arc<Vec<DataType>>, ) -> AggregateUDF { let return_type = Arc::unwrap_or_clone(return_type); let state_type = Arc::unwrap_or_clone(state_type); let state_fields = state_type .into_iter() .enumerate() .map(|(i, t)| Field::new(format!("{i}"), t, true)) .map(Arc::new) .collect::<Vec<_>>(); AggregateUDF::from(SimpleAggregateUDF::new( name, input_type, return_type, volatility, accumulator, state_fields, )) }升级要点:
- 原先
input_type: DataType的写法需要改为向量形式,例如vec![DataType::Float64, DataType::Float64]; - 该函数要求
input_type、state_type与Accumulator的实现严格匹配,签名与状态类型必须一致,否则运行时行为无法保证; - 仓库中该变更的影响面可从测试用例中印证:自定义聚合的参考示例见 datafusion/core/tests/user_defined/user_defined_aggregates.rs,逻辑计划的 proto 往返测试见 datafusion/proto/tests/cases/roundtrip_logical_plan.rs。
2. 数组函数命名体系重构:array_slice/array_element取代array_trim
本版本实现了array_slice和array_element,并移除了array_trim(PR #6936);同时以 SQL 数组函数array_has、array_has_any、array_has_all替换了旧的array_contains(PR #6990),并新增array_repeat(取代array_fill,PR #7199)与array_flatten(PR #7239)。
当前仓库中这些函数的实现集中在 datafusion/functions-nested/src:
- array_has.rs 中
array_has、array_has_any、array_has_all的签名分别通过Signature::array_and_element(Volatility::Immutable)与Signature::arrays(2, None, Volatility::Immutable)构建,即二元数组函数,均为不可变(Immutable)函数; - 切分与提取逻辑位于 extract.rs(
array_slice/array_element相关),重复与展平逻辑位于 repeat.rs。
对使用者而言,需要关注的是 SQL 语义层面的调整:
-- 旧接口(29.0.0 之前) SELECT array_contains([1, 2, 3], 2); SELECT array_trim(...); -- 29.0.0 及之后的新接口 SELECT array_has([1, 2, 3], 2); -- 单个元素判断 SELECT array_has_any([1, 2], [2, 3]); -- 任一命中 SELECT array_has_all([1, 2], [1, 2]); -- 全部命中 SELECT array_slice([1, 2, 3], 2, 3); -- 按区间切片 SELECT array_element([1, 2, 3], 2); -- 按下标取元素 SELECT array_repeat([1], 3); -- 重复生成数组 SELECT array_flatten([[1, 2], [3]]); -- 数组展平3. 字段与列表访问表达式 API 人体工学改进
PR #7215 与配套的 #7218、#7219、#7220 系列重构了创建字段访问(field access)和列表访问(list access)的 API:
- 新增
Expr::field、Expr::index、Expr::slice构造器(PR #7218),替代原先较为冗长的构造方式; - 为
GetFieldAccessExpr增加构造器并补齐文档(PR #7219); - 将
GetFieldAccessCharacteristic重命名并补充文档(PR #7220)。
这一系列改动让表达式树(Expression Tree)在构建字段/索引/切片访问时更加直观,也从侧面表明 DataFusion 在持续打磨 DataFrame 与表达式 DSL 的易用性。
4. Arrow 45.0.0 升级与 Decimal 除法语义变更
PR #6832 将 Arrow 依赖升级至 45.0.0,并同步引入了 Datum Arithmetic(标量值直接参与算术运算)机制,同时改变了 Decimal 除法的语义。这是 29.0.0 中影响面最大的底层变更之一:
- Decimal 除法:除法结果不再按旧的固定精度/标度规则推导,而是遵循 Arrow 45.0.0 的 Datum 算术语义重新定义精度与标度,涉及 DECIMAL 类型的除法结果可能随之变化;
- 同一时期还补充了更多 Decimal256 类型强制转换(PR #7047),并将
Decimal256纳入ScalarValue(PR #7048),Decimal 256 位大精度支持在此版本中进一步完善。
如果你的业务 SQL 中存在高精度 Decimal 除法运算,升级后应重点回归验证精度与舍入行为。
新特性聚焦
线性回归聚合函数家族:regr_*
PR #7211 引入了完整的线性回归聚合函数族,其实现位于 datafusion/functions-aggregate/src/regr.rs。从源码看,该家族共包含 9 个函数,全部以(Float64, Float64)签名注册为不可变聚合(Signature::exact(vec![DataType::Float64, DataType::Float64], Volatility::Immutable)):
| 函数 | 语义(以Y = k*X + b拟合为例) |
|---|---|
regr_slope(Y, X) | 最小残差平方和(RSS)拟合下的斜率 k |
regr_intercept(Y, X) | 最小 RSS 拟合下的截距 b |
regr_count(Y, X) | 两表达式均非空的输入行数 |
regr_r2(Y, X) | 决定系数 R²(Y 中可由 X 解释的方差比例) |
regr_avgx(Y, X) | 自变量 X 的平均值 |
regr_avgy(Y, X) | 因变量 Y 的平均值 |
regr_sxx(Y, X) | X 与其均值偏差的平方和 |
regr_syy(Y, X) | Y 与其均值偏差的平方和 |
regr_sxy(Y, X) | X、Y 偏差乘积之和 |
其中regr_slope是最先落地的一个(PR #7135),其余 8 个随后补齐(PR #7211)。聚合状态通过make_udaf_expr!宏批量生成,回归测试覆盖于 datafusion/sqllogictest/test_files/aggregate.slt。典型用法:
-- 拟合 y = k*x + b SELECT regr_slope(y, x), regr_intercept(y, x), regr_r2(y, x) FROM regression_data;数组包含运算符@>与<@
PR #6885 新增了 PostgreSQL 风格的数组包含/被包含运算符:
SELECT [1, 2, 3] @> [1, 2]; -- true:左数组是否包含右数组 SELECT [1, 2] <@ [1, 2, 3]; -- true:左数组是否被右数组包含该特性与上述array_has_any/array_has_all函数互为补充,分别覆盖"运算符风格"与"函数风格"的数组包含判断。
sqllogictests crate:新的测试框架
PR #7134 新增了独立的sqllogictestscrate(现位于 datafusion/sqllogictest),这是 29.0.0 在工程化层面的重要投入:
- 引擎侧支持多种后端:
datafusion_engine(见 datafusion/sqllogictest/src/engines/datafusion_engine/runner.rs)、postgres_engine(见 datafusion/sqllogictest/src/engines/postgres_engine/mod.rs)以及 Substrait 往返测试引擎; - 测试文件按
.slt格式组织于 datafusion/sqllogictest/test_files,覆盖 aggregate、scalar、math、expr 等大量 SQL 场景; - 该版本同时将原有
information_schema的 Rust 测试迁移至 sqllogictests(PR #7050),后续版本持续把测试收敛到该框架。
datafusion-cli支持多语句输入
PR #7138 让datafusion-cli可以一次性接受并执行多条语句(如粘贴一段包含多条 SQL 的脚本),并配套忽略了查询文件末尾的空白行与注释(PR #7076)。这使得 CLI 的批处理体验更接近标准数据库客户端,相关实现位于 datafusion-cli/src。
其他值得关注的新函数与行为
nanvl内置函数(PR #7171):实现于 datafusion/functions/src/math/nanvl.rs,用于处理 NaN 值场景(如nanvl(x, default)在 x 为 NaN 时返回默认值),测试见 datafusion/sqllogictest/test_files/math.slt;make_array增强(PR #7137、#7207):支持传入列表类型列,并在嵌套版本中完善了 null 处理语义;unnestAPI 调整(PR #7168):与 DuckDB / ClickHouse 行为对齐,新增preserve_nulls选项;count(*)别名修复(PR #7081):修正了聚合投影中count(*)列别名的处理;with_column_renamed大小写敏感支持(PR #7063):支持大小写敏感的列重命名;- 正则表达式简化(PR #7186):支持化简如
~ ^(ba_r|foo)$这类包含下划线的正则表达式。
Bug 修复与稳定性改进
本版本修复了多个会影响查询正确性与稳定性的问题:
- 禁用
interval - timestamp(PR #7086):从类型检查层面直接拒绝该无意义的运算组合,避免运行时出现歧义结果; - 修复 filter 谓词 panic(PR #7126):修复特定谓词组合下执行期 panic;
- 修复多分区错误列需求(PR #7129):修复多分区场景下投影列需求错误导致的错误结果;
- Projection
columns_map移除名称搜索(PR #7099):避免列映射阶段按名称搜索带来的歧义; - SortPreservingMerge 内存记账(PR #7130):为排序保持归并算子补上内存占用统计,配合
MemoryReservation::{split_off, take, new_empty}(PR #7184),让内存限制(memory_limit)机制覆盖更完整; - 压缩相关测试在
--no-default-features下跳过(PR #7172):修复了禁用默认特性时测试失败的问题。
底层重构与性能优化
29.0.0 还包含大量架构级重构,这些改动为后续版本的执行引擎演进奠定基础:
- 排序保持算子配置化(PR #7164):新增 config 选项,允许"有限度地"使用排序保持算子,交由用户权衡收益与内存开销;
- HashJoin 顺序修复(PR #7155)与 join 排序等价性工具函数抽取(PR #7167):统一了 join 输出排序的推导逻辑;
ExecutionPlan访问方式统一(PR #7175):新增ExecutionPlan::file_scan_config,避免大量依赖类型向下转换(downcasting)来获取文件扫描配置;- 模块拆分:
AnalysisContext移出physical_expr(PR #7127)、ExecutionPlanVisitor独立成模块(PR #7236)、streams 移出physical_plan(PR #7234)、Partitioning与Distribution移入physical_expr(PR #7238); - 弃用
batch_byte_size(PR #7245):批次字节大小计算的旧接口被标记弃用; with_inputs()复用原始 schema(PR #7069)与with_preserve_order参数化(PR #7231):减少重复 schema 计算;plan_err!错误宏(PR #7115):统一了 plan 阶段错误构造方式;- 基准测试工具整理:创建
dfbench并拆分 TPCH benchmark runner(PR #7054)、为 benchmark runner 加入 ClickBench 查询(PR #7060)、bench.sh默认只跑 5 次迭代(PR #7189)。
升级注意事项总结
综合来看,从 28.0.0 升级到 29.0.0 时,最需要关注的是以下四点:
- 自定义 UDAF:
create_udaf的input_type参数必须从DataType改为Vec<DataType>(参考 datafusion/expr/src/expr_fn.rs); - 数组 SQL 函数:
array_trim、array_contains、array_fill已被移除,分别迁移到array_slice/array_element、array_has/array_has_any/array_has_all、array_repeat; - Decimal 除法语义:Arrow 45.0.0 升级后,Decimal 除法的精度/标度推导发生变化,涉及金融或高精度计算的查询需重点回归;
- 表达式 API:
Expr::field、Expr::index、Expr::slice与GetFieldAccessExpr构造器的引入意味着程序化构建字段/列表访问的写法已更新。
同时,29.0.0 带来的回归聚合函数族(regr_slope等 9 个函数)、数组包含运算符、nanvl、sqllogictests 测试框架与datafusion-cli多语句支持,都是值得在统计分析与工程化实践中直接采用的新能力。相关函数实现、测试与使用示例均可从上述仓库路径中进一步查阅。
- 大数据
- 数据分析
- 后端
【免费下载链接】datafusion
Apache DataFusion SQL Query Engine
相关推荐
Apache DataFusion 28.0.0 版本解析:数组函数矩阵升级、编码函数落地与执行计划 Graphviz 可视化
Apache DataFusion 28.0.0 版本解析:数组函数矩阵升级、编码函数落地与执行计划 Graphviz 可视化 版本信息 :28.0.0 发布于
大数据数据分析后端Apache DataFusion 6.0.0 版本解析:并发模型重构、函数易失性体系与指标框架全面落地
Apache DataFusion 6.0.0 版本解析:并发模型重构、函数易失性体系与指标框架全面落地 导读 Apache DataFusion 6.0.0(
大数据数据分析后端face-recognition.js 模型训练与保存:构建可复用的人脸识别系统
face recognition.js 模型训练与保存:构建可复用的人脸识别系统 face recognition.js 是一个简单的 Node.js 包,提供
人工智能计算机视觉
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考