从Pyspark数据框创建字典,显示OutOfMemoryError:Java堆空间
我已经看到并尝试了许多关于这个问题的StackOverflow帖子,但是没有一篇有效。我猜我的JAVA堆空间没有我的大数据集预期的大,我的数据集包含650万行。我的Linux实例包含4核64GB Ram。根据这一点,我需要修复我的代码,但我认为从pyspark dataframe制作字典应该不会花费太多。如果有其他方法计算,请告诉我 我只想用我的pyspark数据框架制作一个python字典,这是我的pyspark数据框架的内容从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 +
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,而我们甚至还没有找到字典
首先,您可以只收集所需的列(例如,notname
)。其次,您可以在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收集数据并导致驱动程序故障。没有发生同样的问题