PySpark重新划分RDD元素

时间:2015-06-05 23:06:03

标签: hadoop apache-spark partitioning rdd pyspark

我有一个从Kafka流中读取的spark作业,并为流中的每个RDD执行操作。如果RDD不为空,我想将RDD保存到HDFS,但我想为RDD中的每个元素创建一个文件。我找到了

RDD.saveAsTextFile(file_location)

将为每个分区创建一个文件,因此我尝试更改RDD,使每个分区只包含一个元素。这是我尝试做的一个例子

data = sc.parallelize(['1', '2', '3', '4', '5', '6', '7', '8', '9', '0'])
data.glom().collect() #Produces [['1', '2', '3', '4', '5'], ['6', '7', '8', '9', '0']]
data.saveAsTextFile(file_location) #Produces 2 files

我可以接近我想要的东西,但我无法找到确保每个分区只有一个元素的方法

data1 = data.coalesce(1, True).repartition(data.count())
data1.glom().collect() #Produces [[], ['1', '2', '3', '4', '5'], ['6', '7', '8', '9', '0'], [], [], [], [], [], [], []] 
data2 = data.map(lambda t : t).coalesce(1, True).repartition(data.count())
data2.glom().collect() #Produces [[], ['1'], ['2', '3'], ['4', '5'], ['6'], ['7', '8'], ['9', '0'], [], [], []] 
data2.saveAsTextFile(file_location) #Produces 10 files, but some are empty

我知道在这个例子中我可以将我想要的分区传递给sc.parallelize()但是当我从kafka流中读取时,这是不可能的。关于如何按照我想要的方式重新分配的任何建议,或者如何更好地解决这个问题?

2 个答案:

答案 0 :(得分:2)

下面的python分区器API使用了一个散列分区器,这就是为什么即使你有K个桶你也会得到一些"碰撞"。如果您可以在Scala中执行此操作,则可以提供自定义分区程序(基于范围+桶数== num elems可能会执行此操作)。但是,每个分区有一些开销(并且重新分区是一项昂贵的操作),使用保存逻辑而不是foreach而不是重新分区可能更合理。

答案 1 :(得分:2)

嗯,这是一个用于自定义分区的python解决方案。

(为了清楚起见,将每个元素放在单独的文件中可能不是最好的设计)。

data = sc.parallelize(['1', '2', '3', '4', '5', '6', '7', '8', '9', '0']).map(lambda x: (x,x))
print data.collect()
c = data.count()
wp = data.partitionBy(c,lambda k: int(k))
print wp.map(lambda t: t[0]).glom().collect()
sc.stop()

结果:

[('1', '1'), ('2', '2'), ('3', '3'), ('4', '4'), ('5', '5'), ('6', '6'), ('7', '7'), ('8', '8'), ('9', '9'), ('0', '0')]
[['0'], ['1'], ['2'], ['3'], ['4'], ['5'], ['6'], ['7'], ['8'], ['9']]

希望这有帮助。