以独占方式按键火花RDD分区

时间:2018-11-19 21:56:16

标签: apache-spark pyspark rdd

我想按键对RDD进行分区,并让每个分区仅包含单个键的值。例如,如果我有100个不同的键值,而我repartition(102),则RDD应该有2个空分区和100个分区,每个分区包含一个键值。

我尝试使用groupByKey(k).repartition(102),但这不能保证每个分区中键的排他性,因为我看到有些分区包含更多的单个键值和两个以上的空值。

标准API中是否可以执行此操作?

2 个答案:

答案 0 :(得分:2)

对于RDD,您是否尝试过像partitionBy一样使用this question通过密钥对RDD进行分区?如果需要,可以将分区数指定为要删除空分区的键数。

在数据集API中,您可以将repartitionColumn用作参数,以按该列中的值进行分区(尽管请注意,此操作将spark.sql.shuffle.partitions的值用作分区的数量,因此您将获得更多的空分区。

答案 1 :(得分:1)

要使用partitionBy(),RDD必须包含元组(对)对象。让我们看下面的示例:

假设我有一个包含以下数据的输入文件:

OrderId|OrderItem|OrderDate|OrderPrice|ItemQuantity
1|Gas|2018-01-17|1895|1
1|Air Conditioners|2018-01-28|19000|3
1|Television|2018-01-11|45000|2
2|Gas|2018-01-17|1895|1
2|Air Conditioners|2017-01-28|19000|3
2|Gas|2016-01-17|2300|1
1|Bottle|2018-03-24|45|10
1|Cooking oil|2018-04-22|100|3
3|Inverter|2015-11-02|29000|1
3|Gas|2014-01-09|2300|1
3|Television|2018-01-17|45000|2
4|Gas|2018-01-17|2300|1
4|Television$$|2018-01-17|45000|2
5|Medicine|2016-03-14|23.50|8
5|Cough Syrup|2016-01-28|190|1
5|Ice Cream|2014-09-23|300|7
5|Pasta|2015-06-30|65|2

PATH_TO_FILE="file:///u/vikrant/OrderInputFile"

将文件读入RDD并跳过标题

RDD = sc.textFile(PATH_TO_FILE)
header=RDD.first();
newRDD = RDD.filter(lambda x:x != header)

现在让我们将RDD重新分区为“ 5”个分区

partitionRDD = newRDD.repartition(5)

让我们看看如何在这5个分区中分配数据

print("Partitions structure: {}".format(partitionRDD.glom().collect()))

在这里您可以看到数据被写入两个分区,其中三个是空的,并且没有均匀分布。

Partitions structure: [[], 
[u'1|Gas|2018-01-17|1895|1', u'1|Air Conditioners|2018-01-28|19000|3', u'1|Television|2018-01-11|45000|2', u'2|Gas|2018-01-17|1895|1', u'2|Air Conditioners|2017-01-28|19000|3', u'2|Gas|2016-01-17|2300|1', u'1|Bottle|2018-03-24|45|10', u'1|Cooking oil|2018-04-22|100|3', u'3|Inverter|2015-11-02|29000|1', u'3|Gas|2014-01-09|2300|1'], 
[u'3|Television|2018-01-17|45000|2', u'4|Gas|2018-01-17|2300|1', u'4|Television$$|2018-01-17|45000|2', u'5|Medicine|2016-03-14|23.50|8', u'5|Cough Syrup|2016-01-28|190|1', u'5|Ice Cream|2014-09-23|300|7', u'5|Pasta|2015-06-30|65|2'], 
[], []]

我们需要创建一个RDD对,以使RDD数据均匀地分布在多个分区上。 让我们创建一个RDD对并将其分成键值对。

pairRDD = newRDD.map(lambda x :(x[0],x[1:]))

现在让我们将该rdd重新分区为“ 5”分区,并使用第[0]位的键将数据均匀地分布到这些分区中。

newpairRDD = pairRDD.partitionBy(5,lambda k: int(k[0]))

现在我们可以看到数据是根据匹配的键值对均匀分布的。

print("Partitions structure: {}".format(newpairRDD.glom().collect()))
Partitions structure: [
[(u'5', u'|Medicine|2016-03-14|23.50|8'), 
(u'5', u'|Cough Syrup|2016-01-28|190|1'), 
(u'5', u'|Ice Cream|2014-09-23|300|7'), 
(u'5', u'|Pasta|2015-06-30|65|2')],

[(u'1', u'|Gas|2018-01-17|1895|1'), 
(u'1', u'|Air Conditioners|2018-01-28|19000|3'), 
(u'1', u'|Television|2018-01-11|45000|2'), 
(u'1', u'|Bottle|2018-03-24|45|10'), 
(u'1', u'|Cooking oil|2018-04-22|100|3')], 

[(u'2', u'|Gas|2018-01-17|1895|1'), 
(u'2', u'|Air Conditioners|2017-01-28|19000|3'), 
(u'2', u'|Gas|2016-01-17|2300|1')], 

[(u'3', u'|Inverter|2015-11-02|29000|1'), 
(u'3', u'|Gas|2014-01-09|2300|1'), 
(u'3', u'|Television|2018-01-17|45000|2')], 

[(u'4', u'|Gas|2018-01-17|2300|1'), 
(u'4', u'|Television$$|2018-01-17|45000|2')]
]

下面您可以验证每个分区中的记录数。

from pyspark.sql.functions import desc
from pyspark.sql.functions import spark_partition_id

partitionSizes = newpairRDD.glom().map(len).collect();

[4, 5, 3, 3, 2]

请注意,当您创建键值对的一对RDD时,您的键应为int类型,否则会出现错误。

希望这会有所帮助!