Apache spark 为什么与Spark中应用于DataSet的函数相比,使用sql表达式进行过滤更好

Apache spark 为什么与Spark中应用于DataSet的函数相比,使用sql表达式进行过滤更好,apache-spark,apache-spark-sql,apache-spark-dataset,Apache Spark,Apache Spark Sql,Apache Spark Dataset,我正在读spark ultimat指南书,上面说: 通过指定一个函数,我们迫使spark在数据集中的每一行上计算这个函数……对于简单的过滤器,总是首选编写sql表达式 我不明白为什么sql表达式会更好,因为该表达式也将应用于数据集的每一行

我正在读spark ultimat指南书,上面说:

通过指定一个函数,我们迫使spark在数据集中的每一行上计算这个函数……对于简单的过滤器,总是首选编写sql表达式


我不明白为什么sql表达式会更好,因为该表达式也将应用于数据集的每一行<谁能告诉我更多细节吗

通过使用列表达式,Spark的优化器有机会优化查询,因为它可以“查看”过滤器,并可能将其移动到更好的位置,以提高执行时间

例子: 图像您有一个由两列组成的数据集
id
data
,您的逻辑将首先按
id
列对数据集进行分组,并汇总
数据
值。此分组操作后,仅应保留id为2的组。在这种情况下,先过滤然后求和会更快。通过将过滤器实现为列表达式,Spark可以检测此优化并首先应用过滤器:

val-dfParquet=spark.read.parquet()
val groupedDf=dfParquet.groupBy(“id”).sum(“数据”)
val groupedDfWithColumnFilter=groupedDf.filter(“id=2”)
val groupedDfWithFilterFunction=groupedDf.filter(u.get(0).equals(2))
如果我们检查
groupedDfWithColumnFilter
的执行计划,我们会得到

== Physical Plan == HashAggregate(keys=[id#0L], functions=[sum(data#1L)]) +- Exchange hashpartitioning(id#0L, 200) +- HashAggregate(keys=[id#0L], functions=[partial_sum(data#1L)]) +- Project [id#0L, data#1L] +- Filter (isnotnull(id#0L) && (id#0L = 2)) +- FileScan parquet [id#0L,data#1L] Batched: false, Format: Parquet, Location: InMemoryFileIndex[file:.../id], PartitionFilters: [], PushedFilters: [IsNotNull(id), EqualTo(id,2)], ReadSchema: struct
查看差异的另一种方法是查看Spark UI。对于我的测试用例,我在100个分区中创建了一个包含10百万行的拼花地板文件。 在SQL选项卡中,您可以看到,由于
groupedDfWithColumnFilter
Spark的下推筛选器,因此Spark仅从磁盘加载约20万行数据,而
groupeddfwithfilter函数
Spark需要加载所有1000万行:


通过使用列表达式,Spark的优化器有机会优化查询,因为它可以“查看”过滤器,并可能将其移动到更好的位置以缩短执行时间

例子: 图像您有一个由两列组成的数据集
id
data
,您的逻辑将首先按
id
列对数据集进行分组,并汇总
数据
值。此分组操作后,仅应保留id为2的组。在这种情况下,先过滤然后求和会更快。通过将过滤器实现为列表达式,Spark可以检测此优化并首先应用过滤器:

val-dfParquet=spark.read.parquet()
val groupedDf=dfParquet.groupBy(“id”).sum(“数据”)
val groupedDfWithColumnFilter=groupedDf.filter(“id=2”)
val groupedDfWithFilterFunction=groupedDf.filter(u.get(0).equals(2))
如果我们检查
groupedDfWithColumnFilter
的执行计划,我们会得到

== Physical Plan == HashAggregate(keys=[id#0L], functions=[sum(data#1L)]) +- Exchange hashpartitioning(id#0L, 200) +- HashAggregate(keys=[id#0L], functions=[partial_sum(data#1L)]) +- Project [id#0L, data#1L] +- Filter (isnotnull(id#0L) && (id#0L = 2)) +- FileScan parquet [id#0L,data#1L] Batched: false, Format: Parquet, Location: InMemoryFileIndex[file:.../id], PartitionFilters: [], PushedFilters: [IsNotNull(id), EqualTo(id,2)], ReadSchema: struct
查看差异的另一种方法是查看Spark UI。对于我的测试用例,我在100个分区中创建了一个包含10百万行的拼花地板文件。 在SQL选项卡中,您可以看到,由于
groupedDfWithColumnFilter
Spark的下推筛选器,因此Spark仅从磁盘加载约20万行数据,而
groupeddfwithfilter函数
Spark需要加载所有1000万行: