为何Spark select返回的新DataFrame可以使用父DF未选中的列?
问题原因:Spark Catalyst优化器的谓词下推规则作用
这个现象的核心是Spark SQL的Catalyst优化器执行了谓词下推优化,具体运行逻辑如下:
- 你写的代码执行顺序对应的初始未优化逻辑计划是:
按照未优化的逻辑执行确实应该报错,因为上层Filter要用到的Filter (male = '1') +- Project [name, id] +- Relation [name, id, male](对应你创建的randomDF)male列不在下层Project输出的列列表中。 - 但Catalyst在优化阶段会触发
PushDownPredicate(谓词下推)规则,识别到Filter需要的male列存在于最底层的数据源Relation中,会自动调整执行计划的顺序:- 先把Filter算子移到Project算子的下层,直接对原始的randomDF执行
male='1'的过滤 - 再对过滤后的结果执行
select name, id的投影操作
- 先把Filter算子移到Project算子的下层,直接对原始的randomDF执行
- 调整后的最终执行计划里,所有算子用到的列都在自己的输入中存在,自然不会抛出列不存在的错误,同时得到的结果也和先过滤再选列的结果完全一致。
补充说明
如果你想要关闭这个场景下的优化,强制Spark做上层投影的列存在性检查,可以修改Spark配置:
spark.conf.set("spark.sql.optimizer.pushDownPredicate", false)
关闭后再运行你的代码就会抛出你预期的AnalysisException: Cannot resolve column name "male" among (name, id)错误。
内容的提问来源于stack exchange,提问作者Zxxxxx
相关产品推荐
相关产品推荐

