我很困惑为什么在将生成的RDD转换为DataFrame时,Spark正在使用rdd.mapPartitions
的1个任务。
这对我来说是一个问题,因为我想从:
DataFrame
- > RDD
- > rdd.mapPartitions
- > DataFrame
这样我就可以读取数据(DataFrame),将非SQL函数应用于数据块(RDD上的mapPartitions),然后转换回DataFrame,以便我可以使用DataFrame.write
进程。
我可以从DataFrame转发 - > mapPartitions然后使用像saveAsTextFile这样的RDD编写器,但这不太理想,因为DataFrame.write
进程可以执行诸如以Orc格式覆盖和保存数据之类的操作。所以我想学习为什么这是正在进行的,但从实际的角度来看,我主要关心的是能够从数据框中去 - > mapParitions - >使用DataFrame.write进程。
这是一个可重复的例子。以下按预期工作,mapPartitions
工作有100个任务:
from pyspark.sql import SparkSession
import pandas as pd
spark = SparkSession \
.builder \
.master("yarn-client") \
.enableHiveSupport() \
.getOrCreate()
sc = spark.sparkContext
df = pd.DataFrame({'var1':range(100000),'var2': [x-1000 for x in range(100000)]})
spark_df = spark.createDataFrame(df).repartition(100)
def f(part):
return [(1,2)]
spark_df.rdd.mapPartitions(f).collect()
但是,如果最后一行更改为spark_df.rdd.mapPartitions(f).toDF().show()
,那么mapPartitions
工作只会有一项任务。
答案 0 :(得分:6)
DataFrame.show()
仅显示数据帧的第一行数,默认情况下仅显示前20行。如果该数字小于每个分区的行数,则Spark是惰性的,仅评估单个分区,相当于一项任务。
您还可以对数据框执行collect
,以计算和收集所有分区,并再次查看100个任务。
您仍然会像以前一样首先看到runJob
任务,这是由toDF
调用导致的,以便能够确定生成的数据帧架构:它需要处理单个分区才能够确定映射函数的输出类型。在此初始阶段之后,collect
等实际操作将在所有分区上发生。例如,对于我运行您的代码段,最后一行替换为spark_df.rdd.mapPartitions(f).toDF().collect()
会产生以下阶段: