Apache spark 为什么火花计数操作分三个阶段执行
我已经加载了一个csv文件。将其重新分区为4,然后对数据帧进行计数。当我看到DAG时,我看到这个动作分三个阶段执行 为什么这个简单的动作分为3个阶段执行。我认为第一阶段是加载文件,第二阶段是查找每个分区的计数 那么第三阶段发生了什么 这是我的密码Apache spark 为什么火花计数操作分三个阶段执行,apache-spark,apache-spark-sql,Apache Spark,Apache Spark Sql,我已经加载了一个csv文件。将其重新分区为4,然后对数据帧进行计数。当我看到DAG时,我看到这个动作分三个阶段执行 为什么这个简单的动作分为3个阶段执行。我认为第一阶段是加载文件,第二阶段是查找每个分区的计数 那么第三阶段发生了什么 这是我的密码 val sample = spark.read.format("csv").option("header", "true").option("inferSchema", "true").option("delimiter", ";").load("s
val sample = spark.read.format("csv").option("header", "true").option("inferSchema", "true").option("delimiter", ";").load("sample_data.csv")
sample.repartition(4).count()
StructType schema = new StructType()
.add("key", DataTypes.IntegerType)
.add("value", DataTypes.StringType);
SparkSession session = SparkSession.builder()
.appName("sandbox")
.master("local[*]")
.getOrCreate();
session
.read()
.schema(schema)
.json("file:///C:/<you_path>/dataset")
.repartition(4) // comment on the second run
.registerTempTable("df");
session.sqlContext().sql("SELECT COUNT(*) FROM df").explain();
StructType架构=新的StructType()
.add(“key”,数据类型.IntegerType)
.add(“值”,数据类型.StringType);
SparkSession会话=SparkSession.builder()
.appName(“沙盒”)
.master(“本地[*]”)
.getOrCreate();
一场
.读()
.schema(schema)
.json(“file:///C://dataset")
.repartition(4)//第二次运行时的注释
.注册可撤销(“df”);
session.sqlContext().sql(“从df中选择COUNT(*”).explain();
输出将是:
== Physical Plan ==
*(3) HashAggregate(keys=[], functions=[count(1)])
+- Exchange SinglePartition
+- *(2) HashAggregate(keys=[], functions=[partial_count(1)])
+- Exchange RoundRobinPartitioning(4)
+- *(1) FileScan json [] Batched: false, Format: JSON, Location: InMemoryFileIndex[file:/C:/Users/iaroslav/IdeaProjects/sparksandbox/src/main/resources/dataset], PartitionFilters: [], PushedFilters: [], ReadSchema: struct<>
==物理计划==
*(3) HashAggregate(键=[],函数=[计数(1)])
+-交换单分区
+-*(2)HashAggregate(键=[],函数=[部分计数(1)])
+-Exchange RoundRobinParting(4)
+-*(1)FileScan json[]批处理:false,格式:json,位置:InMemoryFileIndex[文件:/C:/Users/iaroslav/IdeaProjects/sparksandbox/src/main/resources/dataset],分区过滤器:[],PushedFilters:[],ReadSchema:struct
但是,如果您注释/删除.repartition(4)字符串,请注意TableScan和partial_count是在单个阶段内完成的,输出如下所示:
== Physical Plan ==
*(2) HashAggregate(keys=[], functions=[count(1)])
+- Exchange SinglePartition
+- *(1) HashAggregate(keys=[], functions=[partial_count(1)])
+- *(1) FileScan json [] Batched: false, Format: JSON, Location: InMemoryFileIndex[file:/C:/Users/iaroslav/IdeaProjects/sparksandbox/src/main/resources/dataset], PartitionFilters: [], PushedFilters: [], ReadSchema: struct<>
==物理计划==
*(2) HashAggregate(键=[],函数=[计数(1)])
+-交换单分区
+-*(1)HashAggregate(键=[],函数=[部分计数(1)])
+-*(1)FileScan json[]批处理:false,格式:json,位置:InMemoryFileIndex[文件:/C:/Users/iaroslav/IdeaProjects/sparksandbox/src/main/resources/dataset],分区过滤器:[],PushedFilters:[],ReadSchema:struct
另请注意,额外的阶段可能会对性能产生重大影响,因为它需要磁盘I/O(请看一看),并且是影响并行化的某种同步障碍,这意味着在大多数情况下,Spark在第1阶段完成之前不会启动第2阶段。如果
重新分区
提高并行度,可能还是值得的。将推断模式
设置为真
会导致Spark对数据进行一次额外的传递,以发现模式。@hristoilev即使没有推断模式
配置,您也会得到3个阶段。请检查我的answer@VB_我懂了。非常好的解释。谢谢你的回答。这是有道理的。所以这个最终结果聚合任务应该总是在驱动程序上运行?如果我在DF中取一个字段的max()。因此,在每个分区上找到最大值后,最终的值将在驱动程序中找到?@是的,count
将始终将结果拉到驱动程序。我认为max
也可以这样做,否则它如何在分区之间比较结果。但我认为这里的要点是,您不必在这里优化count
操作,因为每个分区只有一个整数被移动到驱动程序。这里最繁重的操作是重新分区
,如果您最初有4个以上的分区,请查看合并
,或者根本不重新分区(如果分区数量合理)。假设您有2个分区,不进行重新分区的情况下,count
可能比重新分区(4)更快。count()
@ѕƒ如果要谈论进一步的优化(假设您控制了CSV文件创建),您可以查看不同的文件格式(柱状拼花地板,对于count
操作,读取单个柱而不是整个文件就足够了)。如果你想继续使用CSV,也要检查压缩选项,而不是需要可拆分的压缩选项。@基于ost的优化器。这意味着使用某些格式(不是CSV格式)或者使用CBO,对于count
操作,Spark不会读取数据,而只读取元数据。在这种情况下,count
应该非常快,并且重新分区
IMHO不需要感谢有价值的注释。我不寻求性能改进。我想了解的是Spark将如何协调结果从不同的执行器中获取数据,并将其聚合以显示最终结果(如果是count或max或其他操作)。我想知道在驱动程序从每个分区获得独立结果后,谁将在驱动程序端聚合数据。从您的回答中,这是将在驱动程序节点上运行的其他任务。
== Physical Plan ==
*(2) HashAggregate(keys=[], functions=[count(1)])
+- Exchange SinglePartition
+- *(1) HashAggregate(keys=[], functions=[partial_count(1)])
+- *(1) FileScan json [] Batched: false, Format: JSON, Location: InMemoryFileIndex[file:/C:/Users/iaroslav/IdeaProjects/sparksandbox/src/main/resources/dataset], PartitionFilters: [], PushedFilters: [], ReadSchema: struct<>