我有一个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()
执行上述操作,这将有效但是会慢得多。
repartition()
/ coalesce()
是唯一正确的方式,哪种更适合这种用法?答案 0 :(得分:1)
我想到的另一个选择是使用repartition()/ coalesce()以减少分区的数量然后 使用mapPartitions()执行上述操作,但这可以工作 会慢得多。
repartition&amp; mapPartitions是相对较快的选项,但你提到它很慢。我认为你可以考虑更传统的解决方案,如multiple-thread reader/writer
1,使用您描述的格式写出结果数据;
2,使用多线程读写器模型将数据并行写入S3存储。工作流程类似于&#34;并行读取器 - 读取 - &gt;并发阻塞队列----&gt;并行编写者---写入-----&gt; S3&#34;。