DataFrame的多个联合会有效吗?

时间:2018-04-16 16:21:06

标签: python apache-spark pyspark apache-spark-sql

我的Python 3程序读取CSV文件,对其执行一些处理,然后将结果转换为DataFrame。 因为CSV文件可能有数百万行,所以我通过驻留在内存中的10,000行批处理,然后将结果转换为DataFrame。

因为我想在Hadoop中形成一个单一的镶木地板文件,我想编写一个大的DataFrame(self.df),它是所有小型数据帧的串联,如下所示:

def parallel_process(self, batch, processor):
    transformed = Pool().map(processor.transform, batch)
    return self.spark.sparkContext.parallelize(transformed).toDF(self.schema)

def process_rows(self, reader, processor):
    line_num = 0
    batch = []
    for row in reader:
        line_num += 1
        # parallel process a batch of 10000 rows
        if line_num % 10000 == 0:
            df = processor.parallel_process(batch)
            if self.df is None:
                self.df = df
            else:
                self.df = self.df.union(df)
            batch.clear()
            print(line_num)
        else:
            batch.append(row)
    # last (incomplete) batch
    df = processor.parallel_process(batch)
    if self.df is None:
        self.df = df
    else:
        self.df = self.df.union(df)

    # write the dataframe
    self.df.write.mode('append').format('parquet').save('table.parquet')

我的问题是,鉴于DataFrames是不可变的,它是内存和计算效率这么做还是应该谨慎使用联合? 如果不是将10,000行的常量大小的批量DF附加到增长较大的DF中,而是将所有批量DataFrame存储在一个数组中(例如),并在最后将它们连接起来,这有可能吗?什么是内存和CPU使用含义?

1 个答案:

答案 0 :(得分:1)

  

因为CSV文件可能有数百万行,所以我会通过驻留在内存中的10,000行来处理,然后将结果转换为DataFrame。

这没有任何意义,并且无法按预期工作。事实上,通过.parallelize传递的所有数据都将存储在Python解释器内存中,并在JVM上进一步复制。

  

因为我想在Hadoop中形成一个单一的镶木地板文件,我想编写一个大的DataFrame(self.df),这是所有小型数据帧的串联,

一般来说,它也不会像这样工作。输出文件的数量不依赖于DataFrames的数量 - 它取决于分区的数量。除非您coalesce(1) / repartition(1)(在任何现实生活场景中很难推荐),否则您将获得多个输出文件。

  

这样做是记忆和计算效率还是应该谨慎使用联合?

本地复杂性在合并DataFrames的数量上是非线性的(过去是指数级的,但在最新版本中实现了改进),因此效率不高。好消息是它不影响任务执行时间,只影响驱动程序代码。

你真正应该做的是,与csv读者一起阅读数据,与parquet作者一起写:

(spark
    .read.format("csv").load(inpath)
    ... # Apply whatever transformations you neeed
    .write.format("parquet").save(outpath))

(根据您的情况适用选项进行调整)。