我想按键对RDD进行分区,并让每个分区仅包含单个键的值。例如,如果我有100个不同的键值,而我repartition(102)
,则RDD应该有2个空分区和100个分区,每个分区包含一个键值。
我尝试使用groupByKey(k).repartition(102)
,但这不能保证每个分区中键的排他性,因为我看到有些分区包含更多的单个键值和两个以上的空值。
标准API中是否可以执行此操作?
答案 0 :(得分:2)
对于RDD,您是否尝试过像partitionBy一样使用this question通过密钥对RDD进行分区?如果需要,可以将分区数指定为要删除空分区的键数。
在数据集API中,您可以将repartition与Column
用作参数,以按该列中的值进行分区(尽管请注意,此操作将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类型,否则会出现错误。
希望这会有所帮助!