web-dev-qa-db-fra.com

reductionByKey: Comment ça marche en interne?

Je suis nouveau sur Spark et Scala. Je ne comprenais pas comment la fonction reductionByKey fonctionne dans Spark. Supposons que nous ayons le code suivant:

val lines = sc.textFile("data.txt")
val pairs = lines.map(s => (s, 1))
val counts = pairs.reduceByKey((a, b) => a + b)

La fonction map est claire: s est la clé et pointe sur la droite de data.txt et 1 est la valeur.

Cependant, je ne comprenais pas comment la réductionByKey fonctionne en interne? Est-ce que "a" pointe vers la clé? Sinon, est-ce que "a" pointe sur "s"? Alors que représente a + b? comment sont-ils remplis?

52
user764186

Décomposons les méthodes et les types discrets. Cela expose généralement les subtilités des nouveaux développeurs:

pairs.reduceByKey((a, b) => a + b)

devient

pairs.reduceByKey((a: Int, b: Int) => a + b)

et renommer les variables le rend un peu plus explicite

pairs.reduceByKey((accumulatedValue: Int, currentValue: Int) => accumulatedValue + currentValue)

Donc, nous pouvons maintenant voir que nous prenons simplement une valeur accumulée pour la clé donnée et la sommons avec la valeur suivante de cette clé. MAINTENANT, passons à autre chose pour que nous puissions comprendre la partie clé. Alors, visualisons la méthode plutôt comme ceci:

pairs.reduce((accumulatedValue: List[(String, Int)], currentValue: (String, Int)) => {
  //Turn the accumulated value into a true key->value mapping
  val accumAsMap = accumulatedValue.toMap   
  //Try to get the key's current value if we've already encountered it
  accumAsMap.get(currentValue._1) match { 
    //If we have encountered it, then add the new value to the existing value and overwrite the old
    case Some(value : Int) => (accumAsMap + (currentValue._1 -> (value + currentValue._2))).toList
    //If we have NOT encountered it, then simply add it to the list
    case None => currentValue :: accumulatedValue 
  }
})

Ainsi, vous pouvez voir que la réduction ByKey permet de rechercher la clé et de la suivre afin que vous n'ayez pas à vous soucier de la gestion de cette partie.

plus profond, plus vrai si vous voulez

Cela étant dit, il s’agit d’une version simplifiée de ce qui se passe car certaines optimisations sont effectuées ici. Cette opération étant associative, le moteur spark effectuera ces réductions localement en premier (souvent appelé réduction au niveau de la carte)), puis de nouveau au niveau du pilote. Cela évite le trafic réseau; les données et l'exécution de l'opération, il peut réduire le plus petit possible et ensuite envoyer cette réduction sur le fil.

86
Justin Pihony

Une des exigences de la fonction reduceByKey est qu’elle doit être associative. Pour construire une certaine intuition sur le fonctionnement de reduceByKey, voyons d'abord comment une fonction associative associative nous aide dans un calcul parallèle:

associative function in action

Comme nous pouvons le constater, nous pouvons décomposer une collection originale en plusieurs morceaux et, en appliquant la fonction associative, nous pouvons accumuler un total. Le cas séquentiel est trivial, nous y sommes habitués: 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10.

L'associativité nous permet d'utiliser la même fonction de manière séquentielle et parallèle. reduceByKey utilise cette propriété pour calculer un résultat à partir d'un RDD, qui est une collection distribuée composée de partitions.

Prenons l'exemple suivant:

// collection of the form ("key",1),("key,2),...,("key",20) split among 4 partitions
val rdd =sparkContext.parallelize(( (1 to 20).map(x=>("key",x))), 4)
rdd.reduceByKey(_ + _)
rdd.collect()
> Array[(String, Int)] = Array((key,210))

Dans spark, les données sont réparties dans des partitions. Pour l'illustration suivante, (4) partitions sont à gauche, délimitées par des lignes fines. Premièrement, nous appliquons la fonction localement à chaque partition, séquentiellement dans la partition, mais nous exécutons les 4 partitions en parallèle. Ensuite, les résultats de chaque calcul local sont agrégés en appliquant la même fonction encore et aboutissent finalement à un résultat.

enter image description here

reduceByKey est une spécialisation de aggregateByKeyaggregateByKey prend deux fonctions: une appliquée à chaque partition (séquentiellement) et une appliquée aux résultats de chaque partition (en parallèle). ) reduceByKey utilise la même fonction associative dans les deux cas: effectuer un calcul séquentiel sur chaque partition, puis combiner ces résultats dans un résultat final, comme nous l'avons illustré ici.

45
maasg

Dans votre exemple de

val counts = pairs.reduceByKey((a,b) => a+b)

a et b sont tous deux Int accumulateurs pour _2 des n-uplets dans pairs. reduceKey prendra deux n-uplets de même valeur s et utilisera leur _2 valeurs comme a et b, produisant un nouveau Tuple[String,Int]. Cette opération est répétée jusqu'à ce qu'il n'y ait qu'un seul Tuple pour chaque clé s.

Contrairement à non -Spark (ou, en réalité, non parallèle) reduceByKey où le premier élément est toujours l'accumulateur et le second une valeur, reduceByKey fonctionne dans un environnement distribué. mode, c’est-à-dire que chaque nœud réduira son ensemble de nuplets en une collection de nuplets à clef unique, puis réduira les nuplets de plusieurs nœuds jusqu’à ce qu’il y ait un ensemble final à clef unique de tuples. Cela signifie que lorsque les résultats des nœuds sont réduits, a et b représentent des accumulateurs déjà réduits.

6
Arne Claassen

La fonction Spark RDD reductionByKey fusionne les valeurs de chaque clé à l’aide d’une fonction de réduction associative.

La fonction reductionByKey ne fonctionne que sur les RDD et il s’agit d’une opération de transformation qui signifie qu’elle est évaluée paresseusement. Et une fonction associative est passée en tant que paramètre, qui est appliqué au RDD source et crée un nouveau RDD en conséquence.

Donc, dans votre exemple, rdd pairs a un ensemble de plusieurs éléments appariés tels que (s1,1), (s2,1), etc. Et variable à la valeur par défaut 0 et additionne l'élément pour chaque clé et renvoie le résultat rdd compte avec le total des comptes appariés avec la clé.

1
KayV