簡體   English   中英

pySpark forEachPartition - 代碼在哪里執行

[英]pySpark forEachPartition - Where is code executed

我在 2.3 版中使用 pySpark(在我當前的開發系統中無法更新到 2.4)並且有以下關於foreachPartition的問題。

首先是一點背景:據我了解,pySpark- UDFs強制 Python 代碼在 Python 實例中的 Java 虛擬機 (JVM) 之外執行,從而降低性能。 由於我需要對我的數據應用一些 Python 函數並希望將開銷成本降至最低,因此我想到了至少將一組可處理的數據加載到驅動程序中並將其作為 Pandas-DataFrame 進行處理。 無論如何,這將導致 Spark 失去並行優勢。 然后我讀到foreachPartition將函數應用於分區內的所有數據,因此允許並行處理。

我現在的問題是:

  1. 當我通過foreachPartition應用 Python 函數時,Python 執行是否發生在驅動程序進程中(分區數據因此通過網絡傳輸到我的驅動程序)?

  2. 數據是在foreachPartition中按行處理的(意味着每個 RDD 行都被一個一個地傳輸到 Python 實例),還是一次處理分區數據(意味着,例如,整個分區被傳輸到實例並由一個 Python 實例整體處理)?

預先感謝您的輸入!


編輯:

我之前使用的驅動程序解決方案看起來像這樣,取自 SO here

for partition in rdd.mapPartitions(lambda partition: [list(partition)]).toLocalIterator():
    # Do stuff on the partition

文檔中可以看出, rdd.toLocalIterator()提供了必要的功能:

返回包含此 RDD 中所有元素的迭代器。 迭代器將消耗與該 RDD 中最大分區一樣多的內存

幸運的是,我偶然發現了 Mrinal 對mapPartitions的精彩解釋( 在此處回答)。

mapPartitions在 RDD 的每個分區上應用一個函數。 因此,如果分區分布在不同的節點上,則可以使用並行化。 在這些節點上創建處理 Python 函數所必需的相應 Python 實例。 雖然foreachPartition僅應用一個函數(例如,將您的數據寫入 a.csv 文件), mapPartitions還返回一個新的 RDD。 因此,使用foreachPartition對我來說是錯誤的選擇。

為了回答我的第二個問題:像mapUDFs這樣的函數會創建一個新的 Python 實例,並逐行傳遞來自 DataFrame/RDD 的數據,從而導致大量開銷。 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|
+-----+

希望這可以幫助面臨類似問題的人:)

pySpark UDF 在執行器附近執行——即在一個獨立的 python 實例中,每個執行器並排運行並在 spark 引擎 (scala) 和 python 解釋器之間來回傳遞數據。

對於在 foreachPartition 中調用 udfs 也是如此

編輯 - 查看示例代碼后

  1. 使用 RDD 並不是使用 spark 的有效方式——你應該轉向數據集
  2. 使您的代碼將所有數據同步到驅動程序的是 collect()
  3. foreachParition 將類似於 glom

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM