PySpark - 如何以稳定和合理快速的方式按键加入两个大型RDD

时间:2017-11-01 02:39:37

标签: pyspark spark-dataframe pyspark-sql

我正在运行 pyspark 应用程序,并且一直收到错误:由于超出内存限制,容器被YARN杀死。使用5.1 GB的5 GB物理内存。

hdfs中有两个数据集, 数据集A如下所示:

a0,{"count":0, "ip":"0.0.0.0"}
a1,{"count":1, "ip":"0.0.0.0"}
a1,{"count":1, "ip":"0.0.0.1"}
a2,{"count":2, "ip":"0.0.0.0"}
a3,{"count":3, "ip":"0.0.0.0"}
...

数据集B看起来像这样:

a0,{"count":0, "ip":"0.0.0.0"}
a1,{"count":1, "ip":"0.0.0.0"}
...

它们都是键,值格式sequenceFile,我想通过键加入A和B,这样我就可以获得如下结果:

a0,{"count":0, "ip":"0.0.0.0"}
a1,{"count":1, "ip":"0.0.0.0"}
a1,{"count":1, "ip":"0.0.0.1"}

并将结果保存为可读格式文件,如textfile或json或csv。

首先我使用cogroup:

rddresult = rddA.cogroup(rddB).filter(lambda x: x[1][0] and x[1][1])

我也使用join:

rddresult = rddA.join(rddB)

但都会遇到内存错误。 然后我想,这可能与groupByKey有关吗?因为它们都使用groupByKey底层。 所以我改变了我的代码,如下所示:

def mergeSeq(a, b):
    ta = type(a)
    tb = type(b)
    if ta == list:
        res = a
    else:
        res = [a]
    if tb == list:
        res.extend(b)
    else:
        res.append(b)
    return res
def filterSeq(li):
    # filtering rows that have no value from rddB
    if type(li) != list:
        return False
    if len(li) <= 1:
        return False
    elif install_pair_flag in li: # install_pair_flag comes from rddB
        return True
    else:
        return False
rddresult = rddA.union(rddB).reduceByKey(mergeSeq).filter(filterSeq) 
# repartition seems to solve memory error but dramatically slow down the speed
# rddresult = rddA.union(rddB).reduceByKey(mergeSeq).filter(filterSeq).repartition(numPartitions=9092)

再次出现内存错误。

我会根据article

的说明调整我的火花配置
spark-submit --master yarn-cluster --name yy-adtracking --conf spark.akka.frameSize=2000 --conf spark.yarn.maxAppAttempts=1 --conf spark.yarn.executor.memoryOverhead=12000  --num-executors 24 --driver-memory 4g --executor-memory 2g --executor-cores 1 runjob.py

但它没有帮助。

最后,我将rdd转换为dataframe:

sqlctx = SQLContext(SC)
dfA = sqlctx.createDataFrame(rddA, ["k", "v0"])
dfB = sqlctx.createDataFrame(rddB, ["k", "v1"])
dfresult = dfA.join(dfB, on="k", how="inner")
dfresult.write.json(path, "overwrite")
好吧,它没有报告内存错误,也更快。 但是当把json写入磁盘时,它变得非常慢,几乎是计算的四倍。

所以这是我的问题: 有没有更稳定合理的快速解决方案来完成我的任务?或者我应该坚持使用当前的方法,使用重新分区或数据框?

0 个答案:

没有答案