pySpark forEachPartition-代码在哪里执行

时间:2019-04-12 15:27:47

标签: python pandas apache-spark pyspark

我正在使用2.3版的pySpark(无法在当前的开发系统中更新到2.4版),并且对foreachPartition有以下疑问。

首先介绍一下上下文:据我了解,pySpark-UDFs强制在驱动程序进程中执行Python代码,从而降低了性能。 因为我需要对数据应用一些Python函数,并且希望防止每一行都对驱动程序进行单个函数调用(UDF会这样做),所以我的想法是至少将一堆可处理的数据加载到驱动程序中,将其作为Pandas-DataFrame处理。 然后我读到说foreachPartition进程将函数应用于分区中的所有数据,因此允许并行处理。

我的问题是:

  1. 当我通过foreachPartition应用Python函数时,在驱动程序进程中是否发生了UDFs的Python执行类似物(因此分区数据是通过网络传输的)给我的司机)?

  2. 是仍在foreachPartition内按行处理数据(意味着每个RDD行都需要执行新的Python执行),还是一次处理了分区数据(例如,整个分区被转移到驱动程序,并由一个Python执行作为一个整体来处理,例如作为Pandas-DataFrame)?

提前感谢您的输入!

编辑: 我当前的“驱动程序中”-解决方案如下:

def partition_generator(rdd):
    glom = rdd.glom()
    #Optionally persist glom
    for partition in range(rdd.getNumPartitions()):
        yield glom.map(lambda row: row[partition]).collect()

2 个答案:

答案 0 :(得分:0)

pySpark UDF在执行器附近执行-即每个执行器在一个单独的python实例中并排运行,并在Spark引擎(scala)和python解释器之间来回传递数据。

对于foreachPartition中的udfs的调用也是如此

编辑-查看示例代码后

  1. 使用RDD并不是使用Spark的有效方法-您应该移动 到数据集
  2. 使代码将所有数据同步到驱动程序的原因是collect()
  3. foreachParition将类似于glom

答案 1 :(得分:-1)

幸运的是,我偶然发现了Mrinal对mapPartitions的出色解释(回答here)。

mapPartitions在RDD的每个分区上应用一个功能。因此,如果分区分布在不同的节点上,则可以使用并行化。在这些节点上创建了处理Python函数所必需的相应Python实例。 尽管foreachPartition仅应用函数(例如,将数据写入.csv文件),但mapPartitions也返回新的RDD。因此,使用foreachPartition对我来说是错误的选择。

为了回答我的第二个问题:mapUDFs之类的函数会为DataFrame / RDD的每一行创建一个新的Python实例,从而导致大量开销。 foreachPartitionmapPartitions(两个RDD函数)将整个分区转移到Python实例,因此需要的实例数量要少得多。

此外,使用生成器还减少了迭代此传输的分区数据所需的内存量(将分区作为迭代器对象处理,然后通过对该对象进行迭代来处理每一行)。

一个例子可能像这样:

def generator(partition):
    """
    Function yielding some result created by some function applied to each row of a partition (in this case lower-casing a string)

    @partition: iterator-object of partition
    """

    for row in partition:
        yield [word.lower() for word in row["text"]]


df = spark.createDataFrame([(["TESTA"], ), (["TESTB"], )], ["text"])
df = df.repartition(2)
df.rdd.mapPartitions(generator).toDF(["text"]).show()


#Result:
+-----+
| text|
+-----+
|testa|
|testb|
+-----+

希望这可以帮助面临类似问题的人:)