Pyspark。内存不足的问题。如何确保表格被覆盖

时间:2018-12-09 14:59:32

标签: python apache-spark memory machine-learning pyspark

我目前试图了解Spark计算的过程以及对内存消耗的影响。

我正在使用Zeppelin中的Spark 2.3.2和Python 2.7。

基本上在以下循环中,我将创建集合。我正在使用sci-kit-learn建立一个机器学习模型,并且在计算sci-kit-learn之后,我正在pyspark-dataframes上进行了很多数据框操作。对于每个我,我都会得到一个表rsmeMaeStep,该表具有8行和10列,具有小的字符串或双精度值。 rsmeMaeAll只是将单个分析加在一起,并具有8 * 26 = 208行和10列,其中i = 26。

for i in range(26):
    df_features_train, df_features_validation = randomizer(dataFiltered)
    rsmeMaeStep, rsmeMaeAll = rsmeMaeAnalysis(rsmeMaeAll,df_features_train,df_features_test)
    print(i)

我对代码做了一些时间分析。对于i = 1,i = 10花费了17秒:2:40对于i = 26花费了6:42。 (即10或26个循环的时间长9.4或23.6倍。)到目前为止,一切都如预期。 下一步我有问题。以下代码仅需对8到206行进行简单汇总。对于i = 1,它花费了32秒,对于i = 7 4:43(是8.8倍),但是对于i = 26,我在47分钟后拥有0%的信息,否则它会因内存不足消息而失败。

rsmeMae = rsmeMaeAll.select('set','setting','sme').orderBy('set','setting')
import pyspark.sql.functions as f
rsmeMaeAverage = rsmeMae.groupBy('setting','set').agg(f.count(('setting')).alias('nrOfRand'), f.round(f.mean('sme'),2).alias('rsme'),f.round(f.stddev('sme'),2).alias('sigmaRsme')).orderBy('set','setting')
z.show(rsmeMaeAverage)

基于逻辑,我认为所有表都应在每个循环中被覆盖。在每个循环中,只有小的rsmeMaeAll应该增加一点。但这仍然是一张很小的桌子。

但是Spark的行为可能有所不同。

据我所知,第一步的sk-learn代码是在第一步中执行的。如果我确实正确理解了火花延迟评估,那么当我要打印结果时,代码中的pySpark操作就会开始执行。因此,Spark可能会将所有循环的所有表保存在内存中。是吗?

如果我是对的,我将需要代码直接在每个循环结束时计算pySpark代码。

我该怎么办?

如果我这样做,将在下一个循环中触发覆盖表,还是每个循环的内存消耗仍会增加?我需要主动从内存中删除表吗?

编辑:我刚刚集成

rsmeMaeStep.collect()
rsmeMaeAll.collect()

进入循环以确保pyspark计算立即完成。 但是,虽然第一次循环花了55秒。第7个耗时超过10分钟,在49分钟之后,它在第8个循环的rsmeMaeAll.collect()处崩溃。错误消息:

  

Py4JJavaError:调用o13488.collectToPython时发生错误。 :java.lang.OutOfMemoryError:Java堆空间

我真的不明白每个循环的时间呈指数增长。在我至少能够运行10个循环之前。那里发生了什么事?

1 个答案:

答案 0 :(得分:0)

我认为问题与Spark中的延迟评估有关。并且由于收集了所有信息,因此在我尝试计算输出时,可能同时将pyspark数据框rsmeMaeAll生成rsmeMaeAll所需的所有信息都加载到了缓存中。

基于这个想法,我以不需要Spark保留所有步骤的方式来重建代码。此外,我集成了时间测量功能,并以两个变体重建了旧代码,以使一个变体更接近于新逻辑以及每个变体,从而必须在每个循环结束时进行计算。

解决方案如下:

for i in range(9):
    ti0 = time.time()
    df_features_train, df_features_test = randomizer(dataFiltered)
    rsmeMaeStep = rsmeMaeAnalysis(df_features_train,df_features_test)
    rsmeMaeAllpd = rsmeMaeAllpd.append(rsmeMaeStep.toPandas())
    print(rsmeMaeAllpd)
    ti1 = time.time()
    print "Time for loop", i, ":", ti1-ti0

在rsmeMaeAnalysis中,我刚刚计算了分析结果,将其返回,将其转换为Pandas数据框,并在Pandas中收集了所有结果。结果是每个循环或多或少地花费了相同的时间,即使经过20个循环,我也没有出现内存问题。前十个循环的时间如下:

  

41s,42s,44s,40s,43s,43s,40s,39s,40s,40s

但是随后我想确保在pyspark数据框中确实收集结果是问题,因此我构建了一个尽可能接近pandas解决方案的代码,但在pyspark数据框中收集了结果:

for i in range(10):
    ti0 = time.time()
    df_features_train, df_features_test = randomizer(dataFiltered)
    rsmeMaeStep = rsmeMaeAnalysis(df_features_train,df_features_test)
    rsmeMaeAll = rsmeMaeAll.union(rsmeMaeStep)
    rsmeMaeAll.show(80,False)
    ti1 = time.time()
    print "Time for loop", i, ":", ti1-ti0

前八个循环的时间如下:

  

43s,63s,88s,144s,162s,175s,212s,276s

在最初的带有时间测量的变体中,它花费了以下时间,直到第7次循环后出现内存不足错误为止:

  

44s,60s,73s,98s,128s,157s,198s

最后,stil似乎是惰性评估,导致产生rsmeMaeAll所需的大量信息已同时加载到高速缓存中,尽管大多数信息在每个循环结束时都不相关。