Pourquoi un RDD cloisonné n'a pas besoin d'être brassés?
Lorsque l'auteur fait:
val links = sc.objectFile[(String, Seq[String])]("links")
.partitionBy(new HashPartitioner(100))
.persist()
Il partitionner l'ensemble des données en 100 partitions où chaque clé sera HASHED à une partition donnée (pageId
dans l'exemple donné). Cela signifie que la même clé sera stockée dans une seule partition donnée . Puis, quand il fait le join
:
val contributions = links.join(ranks)
Tous les blocs de données avec le même pageId
devraient déjà se trouver sur le même exécuteur testamentaire, ce qui évite la nécessité d'un remaniement entre les différents nœuds du cluster.
PartitionBy() est une transformation large, donc il va produire shuffle de toute façon, non?
Oui, partitionBy
produit un ShuffleRDD[K, V, V]
:
def partitionBy(partitioner: Partitioner): RDD[(K, V)] = self.withScope {
if (keyClass.isArray && partitioner.isInstanceOf[HashPartitioner]) {
throw new SparkException("HashPartitioner cannot partition array keys.")
}
if (self.partitioner == Some(partitioner)) {
self
} else {
new ShuffledRDD[K, V, V](self, partitioner)
}
}
Quelqu'un pourrait-il illustrer un exemple concret et ce qui se passe dans chaque un seul nœud lorsque partitionBy arrive?
Fondamentalement, partitionBy
va effectuer les opérations suivantes:
Il sera hachage la clé modulu le nombre de partitions (100 dans ce cas), et comme il relys sur le fait que le même key produira toujours le même hashcode, il va empaqueter toutes les données d'un identifiant donné (dans notre cas, pageId
) à la même partition, de sorte que lorsque vous join
, toutes les données seront déjà disponibles dans cette partition, évitant ainsi le besoin d'un shuffle.
Merci beaucoup pour votre réponse @Yuval. – Giorgio
Mais si pour éviter shuffle lors de la jointure, nous devons faire un remaniement au début, quel est l'avantage? Peut-être juste quand le RDD partitionné est utilisé plusieurs fois? Ou quoi? – Giorgio
@Giorgio Si nous n'avions pas prématurément partitionné le RDD et l'avons persisté, alors chaque itération sur lui entraînerait un shuffle. La façon dont nous remodelons une fois et réutilisons plusieurs fois nous économise l'overhead dans les prochaines itérations. –