从spark rdd收集大型数据集的最佳做法是什么?

时间:2016-05-21 22:31:20

标签: dataset pyspark collect

我正在使用pyspark处理我的数据,最后我需要使用rdd.collect()从rdd收集数据。但是,由于内存问题,我的火花会崩溃。我尝试了很多方法,但没有运气。我现在使用以下代码运行,为每个分区处理一小块数据:

def make_part_filter(index):
    def part_filter(split_index, iterator):
        if split_index == index:
            for el in iterator:
                yield el
    return part_filter


for part_id in range(rdd.getNumPartitions()):
    part_rdd = rdd.mapPartitionsWithIndex(make_part_filter(part_id), True)
    myCollection = part_rdd.collect()
    for row in myCollection:
          #Do something with each row

我目前使用的新代码没有崩溃,但似乎永远在运行。

有没有更好的方法从大型rdd收集数据?

2 个答案:

答案 0 :(得分:2)

尝试"收集"一个巨大的RDD是有问题的。 "收集"返回一个列表,这意味着整个RDD内容必须存储在驱动程序的内存中。这是一个" showstopper"问题。通常,人们希望Spark应用程序能够处理大小远远超出单个节点内存的数据集。

假设RDD几乎不适合记忆,并且"收集"作品。然后我们有另一个" showstopper" ---性能低下。在您的代码中,收集的RDD在循环中处理:"用于myCollection中的行"。该循环仅由一个核心执行。因此,不是通过RDD处理数据,而RDD的计算分布在集群的所有核心中,如果不是1000,则可能有100个 - 而不是整个数据集上的所有工作放在单个核心的背面。

答案 1 :(得分:1)

我不知道这是不是最好的方式,但这是我尝试过的最佳方式。不确定它是否比你的更好或更差。同样的想法,将它分成块,但你可以更灵活地使用块大小。

def rdd_iterate(rdd, chunk_size=1000000):
    indexed_rows = rdd.zipWithIndex().cache()
    count = indexed_rows.count()
    print("Will iterate through RDD of count {}".format(count))
    start = 0
    end = start + chunk_size
    while start < count:
        print("Grabbing new chunk: start = {}, end = {}".format(start, end))
        chunk = indexed_rows.filter(lambda r: r[1] >= start and r[1] < end).collect()
        for row in chunk:
            yield row[0]
        start = end
        end = start + chunk_size

示例用法我想在磁盘上的CSV文件中附加一个巨大的RDD而不用整个RDD填充Python列表:

def rdd_to_csv(fname, rdd):
    import csv
    f = open(fname, "a")
    c = csv.writer(f)
    for row in rdd_iterate(rdd): # with abstraction, iterates through entire RDD
        c.writerows([row])
    f.close()

rdd_to_csv("~/test.csv", my_really_big_rdd)
相关问题