从Pyspark数据框创建字典,显示OutOfMemoryError:Java堆空间

从Pyspark数据框创建字典,显示OutOfMemoryError:Java堆空间,java,python,apache-spark,pyspark,Java,Python,Apache Spark,Pyspark,我已经看到并尝试了许多关于这个问题的StackOverflow帖子,但是没有一篇有效。我猜我的JAVA堆空间没有我的大数据集预期的大,我的数据集包含650万行。我的Linux实例包含4核64GB Ram。根据这一点,我需要修复我的代码,但我认为从pyspark dataframe制作字典应该不会花费太多。如果有其他方法计算,请告诉我 我只想用我的pyspark数据框架制作一个python字典,这是我的pyspark数据框架的内容 property\u sql\u df.show()shows +

我已经看到并尝试了许多关于这个问题的StackOverflow帖子,但是没有一篇有效。我猜我的JAVA堆空间没有我的大数据集预期的大,我的数据集包含650万行。我的Linux实例包含4核64GB Ram。根据这一点,我需要修复我的代码,但我认为从pyspark dataframe制作字典应该不会花费太多。如果有其他方法计算,请告诉我

我只想用我的pyspark数据框架制作一个python字典,这是我的pyspark数据框架的内容

property\u sql\u df.show()
shows

+--------------+------------+--------------------+--------------------+
|            id|country_code|       name|          hash_of_cc_pn_li|
+--------------+------------+--------------------+--------------------+
|  BOND-9129450|          US|Scotron Home w/Ga...|90cb0946cf4139e12...|
|  BOND-1742850|          US|Sited in the Mead...|d5c301f00e9966483...|
|  BOND-3211356|          US|NEW LISTING - Com...|811fa26e240d726ec...|
|  BOND-7630290|          US|EC277- 9 Bedroom ...|d5c301f00e9966483...|
|  BOND-7175508|          US|East Hampton Retr...|90cb0946cf4139e12...|
+--------------+------------+--------------------+--------------------+
我想要的是制作一个字典,其中hash_of_cc_pn_li为key,id为一个list

预期产出

{
  "90cb0946cf4139e12": ["BOND-9129450", "BOND-7175508"]
  "d5c301f00e9966483": ["BOND-1742850","BOND-7630290"]
}
ERROR:py4j.java_gateway:An error occurred while trying to connect to the Java server (127.0.0.1:33097)
到目前为止我已经尝试过的,

%%time
duplicate_property_list = {}
for ind in property_sql_df.collect(): 
     hashed_value = ind.hash_of_cc_pn_li
     property_id = ind.id
     if hashed_value in duplicate_property_list:
         duplicate_property_list[hashed_value].append(property_id) 
     else:
         duplicate_property_list[hashed_value] = [property_id] 
我现在在控制台上看到的内容:

java.lang.OutOfMemoryError:java堆空间

并在Jupyter笔记本输出上显示此错误

{
  "90cb0946cf4139e12": ["BOND-9129450", "BOND-7175508"]
  "d5c301f00e9966483": ["BOND-1742850","BOND-7630290"]
}
ERROR:py4j.java_gateway:An error occurred while trying to connect to the Java server (127.0.0.1:33097)
从pyspark数据帧制作字典应该不会花费太多

这在运行时方面是正确的,但这很容易占用大量空间。尤其是当您正在执行
属性\u sql\u df.collect()
,此时您正在将整个数据帧加载到驱动程序内存中。在6.5M行中,如果每行有10KB或10K个字符,您将达到65GB,而我们甚至还没有找到字典

首先,您可以只收集所需的列(例如,not
name
)。其次,您可以在Spark中进行上游聚合,这将节省一些空间,具体取决于每个
hash\u cc\u pn\u li的
id有多少:

rows = property_sql_df.groupBy("hash_of_cc_pn_li") \
  .agg(collect_set("id").alias("ids")) \
  .collect()

duplicate_property_list = { row.hash_of_cc_pn_li: row.ids for row in rows }

以下是如何使用数据制作示例数据框:

数据=[
(“债券-9129450”、“90cb”),
(“债券-1742850”,“d5c3”),
(“债券-3211356”,“811f”),
(“债券-7630290”,“d5c3”),
(“债券-7175508”、“90cb”),
]
df=spark.createDataFrame(数据,[“id”,“哈希”\u cc\u pn\u li])
让我们在Spark数据帧中聚合数据,以限制在驱动程序节点上收集的行数。我们将使用中定义的
two_columns\u to_dictionary
函数创建字典

agg_df=df.groupBy(“hash_of_cc_pn_li”).agg(F.max(“hash_of_cc_pn_li”).alias(“hash”)、F.collect_list(“id”).alias(“id”))
res=quinn.两列到字典(agg_-df,“hash”,“id”)
打印(res)#=>{'811f':['BOND-3211356'],'d5c3':['BOND-1742850','BOND-7630290'],'90cb':['BOND-9129450','BOND-7175508']
这可能适用于相对较小的650万行数据集,但不适用于大型数据集。“我认为从pyspark数据帧制作字典不应该太昂贵”,这只适用于非常小的数据帧。从PySpark数据帧制作字典实际上非常昂贵

PySpark是一个集群计算框架,它通过将数据分散在集群中的节点上而受益。当您调用
collect
时,所有数据都会移动到驱动程序节点,而工作程序节点不会提供帮助。每当您尝试将太多数据移动到驱动程序节点时,就会出现OutOfMemory异常


最好完全避免使用字典,并找出一种不同的方法来解决这个问题。很好的问题。

Spark-2.4
我们可以使用
groupBy,collect\u list,map\u From\u Array,to\u json
内置函数来解决这个问题

示例:

df.show()
#+------------+-----------------+
#|          id| hash_of_cc_pn_li|
#+------------+-----------------+
#|BOND-9129450|90cb0946cf4139e12|
#|BOND-7175508|90cb0946cf4139e12|
#|BOND-1742850|d5c301f00e9966483|
#|BOND-7630290|d5c301f00e9966483|
#+------------+-----------------+
df.groupBy(col("hash_of_cc_pn_li")).\
agg(collect_list(col("id")).alias("id")).\
selectExpr("to_json(map_from_arrays(array(hash_of_cc_pn_li),array(id))) as output").\
show(10,False)
#+-----------------------------------------------------+
#|output                                               |
#+-----------------------------------------------------+
#|{"90cb0946cf4139e12":["BOND-9129450","BOND-7175508"]}|
#|{"d5c301f00e9966483":["BOND-1742850","BOND-7630290"]}|
#+-----------------------------------------------------+
要获取
一个dict
请使用另一个agg和
收集列表

df.groupBy(col("hash_of_cc_pn_li")).\
agg(collect_list(col("id")).alias("id")).\
agg(to_json(map_from_arrays(collect_list(col("hash_of_cc_pn_li")),collect_list(col("id")))).alias("output")).\
show(10,False)
#+---------------------------------------------------------------------------------------------------------+
#|output                                                                                                   |
#+---------------------------------------------------------------------------------------------------------+
#|{"90cb0946cf4139e12":["BOND-9129450","BOND-7175508"],"d5c301f00e9966483":["BOND-1742850","BOND-7630290"]}|
#+---------------------------------------------------------------------------------------------------------+

为子孙后代添加链接帖子的公认答案。解决方法是利用
write.json
方法并防止向驱动程序收集过大的数据集:


不确定它最终是否有用,但作为第一步,您可以尝试将列表集合作为
df.groupby(“hash\u of\u cc”).agg(collect\u list(“id”)).show()分发。然后再仔细看一看,决定你是否真的需要收集完整的数据帧给驱动程序。谢谢你详细的回答,先生。只是一个简单的问题。当我尝试使用df.toPandas()将pyspark数据帧转换为pandas时,同样的错误发生了,在这种情况下我该怎么办?@AlwaysSunny-Yep,toPandas还收集驱动程序节点上的所有数据,除非数据集很小,否则应该避免使用。没有相同的问题occuring@AlwaysSunny-是的,这并不奇怪,这是一个常见的错误,每当你试图收集一个大数据集。请随意问另一个问题,解释您试图用字典完成的任务,我可以看看是否有其他方法可以用另一种方法解决您的问题。感谢您详细的回答,先生。只是一个简单的问题。当我尝试使用df.toPandas()将pyspark数据框转换为pandas时,发生了相同的错误,在这种情况下我该怎么办?
df.toPandas()
在占用空间方面甚至比
df.collect()
更糟糕。做什么取决于你在这之后要做什么。比如说,如果只是要有一个带有这些映射的csv文件,那么您可以直接从数据帧(使用
collect_list
/
collect_set
)开始,并通过
df.coalesce(1.write.option('sep',';').csv(path)将其保存到一个文件中
。没有运气出现同样的问题后续问题:谢谢你详细的回答,先生。我使用spark 3.0,所以我可以使用collect\u List只是一个简单的问题当我尝试使用df.toPandas()将pyspark数据框转换为pandas时发生了同样的错误,在这种情况下我该怎么办?@AlwaysAnny,尽量避免转换为数据帧,如果可能,使用内置的spark函数来获得预期的输出。pandas收集数据并导致驱动程序故障。没有发生同样的问题