将每个Spark RDD条目分别保存到S3

时间:2015-12-30 21:01:59

标签: amazon-s3 apache-spark pyspark

我有一个PySpark应用程序(显然)加载和转换数据。

我想将结果RDD保存到S3,但Spark提供的.saveAsTextFile()函数不满足我的要求,因为它将多个RDD条目写入一个文件。

例如,我们假设RDD resultRDD是:

[('cats', cats_data), ('dogs', dogs_data), ('flamingos', flamingos_data)]

调用resultRDD.saveAsTextFile(s3n://path/to/somewhere/)时,它会创建多个文件,如下所示:

1. 000_part00 [containing cats_data & dogs_data]
2. 000_part01 [containing only flamingos_data]

请注意,创建的文件数与RDD中的元素数无关。此外,在打开文件之前,我甚至无法知道每个文件中的内容。

相反,我想要创建的是以下输出:

1. cats [containing only cats_data]
2. dogs [containing only dogs_data]
2. flamingos [containing only flamingos_data]

我以为我可以使用boto' S3Connection并手动写入S3,如下所示:

s3_connection = <connecting to S3 here>
bucket = s3_connection.get_bucket('animals_data')

def persist_to_s3(data_tuple):
   s3_key = bucket.create_key(key=data_tuple[0], bucket=bucket)
   s3_key.set_contents_from_string(data_tuple[1])

resultRDD.map(persist_to_s3)

不幸的是,连接和存储桶对象既不是可序列化的也不是线程安全的(我推测),所以我不能像上面那样共享节点之间的连接。

我以为我可能会连接到S3&amp;在persist_to_s3函数本身中获取存储桶,但是此操作肯定会使AWS限制我的API使用,因为我有一个大规模的RDD。

澄清:我的实际数据集非常庞大,而且密钥都是唯一的。因此,在这种情况下,按键重新分区不会有帮助。

我想到的另一个选择是使用repartition() / coalesce()来减少分区数量,然后使用mapPartitions()执行上述操作,这将有效但是会慢得多。

  • 我还能做些什么才能以我描述的格式快速将数据保存到S3?
  • 如果使用repartition() / coalesce()是唯一正确的方式,哪种更适合这种用法?

1 个答案:

答案 0 :(得分:1)

  

我想到的另一个选择是使用repartition()/   coalesce()以减少分区的数量然后   使用mapPartitions()执行上述操作,但这可以工作   会慢得多。

repartition&amp; mapPartitions是相对较快的选项,但你提到它很慢。我认为你可以考虑更传统的解决方案,如multiple-thread reader/writer

1,使用您描述的格式写出结果数据;
2,使用多线程读写器模型将数据并行写入S3存储。工作流程类似于&#34;并行读取器 - 读取 - &gt;并发阻塞队列----&gt;并行编写者---写入-----&gt; S3&#34;。