Explication des variables partagées dans SparkCore

1. Accumulateur RDD1

  • Il n'est pas possible d'accumuler directement dans le programme distribué lui-même, il a besoin de l'aide de variables partagées
  • Dans un programme distribué, la valeur définie du côté Pilote effectue des calculs réels du côté Exécuteur. Lorsque l'Exécuteur est exécuté, la valeur n'est pas renvoyée du côté Pilote, de sorte que le Pilote ne peut pas obtenir le résultat.
  • Cela conduit donc aux variables partagées entre le pilote et l'exécuteur. La valeur définie sur le pilote peut renvoyer le résultat directement après le calcul de l'exécuteur.

Lead: L' accumulateur fourni par Spark est principalement utilisé pour les opérations partagées sur une variable par plusieurs nœuds

  1. sc.accumulateur (0)
  2. sc.longaccumulater (0) // Utilisez ceci
  3. acccount.add ()
  • Utiliser l'accumulateur: généralement lorsque vous passez des fonctions à Spark, comme l'utilisation de la fonction map () ou l'utilisation de filter () pour passer des conditions, vous pouvez utiliser les variables définies dans le programme du pilote, mais chaque tâche exécutée dans le cluster obtiendra ces variables Pour une nouvelle copie, la mise à jour des valeurs de ces copies n'affectera pas les variables correspondantes dans le pilote. À ce stade, l'accumulateur peut être utilisé pour obtenir l'effet souhaité.
    val xx: Accumulateur [Int] = sc.accumulator (0)

Démo de code: collection Scala

import org.apache.spark.rdd.RDD
import org.apache.spark.util.LongAccumulator
import org.apache.spark.{
    
    Accumulator, SparkConf, SparkContext}

/**
 * @author liu a fu
 * @date 2021/1/17 0017
 * @version 1.0
 * @DESC    演示Spark的共享变量之累加器
 */
object SparkAddCumulater {
    
    

 val conf: SparkConf = new SparkConf().setAppName(this.getClass.getSimpleName.stripSuffix("$")).setMaster("local[*]")

  def main(args: Array[String]): Unit = {
    
    
    val sc = new SparkContext(conf)
    //实验1 Scala中的累加器
    val arr = Seq(1, 2, 3)
    var  count1 = 0
    arr.foreach(x => count1 += x)
    println(count1)   //6

    //实验2  RDD的累加器
    //因为定义变量在driver端定义,但是rdd的数值的计算在exector中执行的,执行完毕后没有直接返回driver端,看不到结果
    var count2=0
    val rdd1: RDD[Int] = sc.parallelize(arr)
    rdd1.foreach(x => count2 +=x)
    println(count2)   //0


    //实验3:构建在Driver端和Executor的共享的变量
    val count3: Accumulator[Int] = sc.accumulator(0) //底层实现的+=,仅仅能够在driver访问  过时
    rdd1.foreach(x => count3.add(x))
    println(count3)   //6

    //实验4:使用建议使用的方法
    //Create and register a long accumulator, which starts with 0 and accumulates inputs by `add`.  源码解释
    val count4: LongAccumulator = sc.longAccumulator("count4")
    rdd1.foreach(x => count4.add(x))
    println(count4)  //LongAccumulator(id: 51, name: Some(count4), value: 6)
    println(count4.value)  //6

  }
}

2. Variable de diffusion RDD2

Principe:
Les variables de diffusion permettent aux développeurs de mettre en cache des variables en lecture seule dans chaque nœud (Worker ou Executor) au lieu de passer ces variables entre les tâches. L'utilisation de variables de diffusion permet de créer efficacement des copies de grands ensembles de données sur chaque nœud du cluster. Dans le même temps, Spark utilise également des algorithmes de diffusion efficaces pour distribuer ces variables, réduisant ainsi la surcharge de communication.
Insérez la description de l'image ici
Cas:
Insérez la description de l'image ici
Démonstration de code: Définissez une structure de données d'un tableau id + fruit. Ici vous pouvez trouver des fruits par id

import org.apache.spark.broadcast.Broadcast
import org.apache.spark.rdd.RDD
import org.apache.spark.{
    
    SparkConf, SparkContext}

/**
 * @author liu a fu
 * @date 2021/1/17 0017
 * @version 1.0
 * @DESC   演示广播变量
 */
object SparkBroadcast {
    
    

  def main(args: Array[String]): Unit = {
    
    
    val conf: SparkConf = new SparkConf().setAppName(this.getClass.getSimpleName.stripSuffix("$")).setMaster("local[*]")
    val sc = new SparkContext(conf)

    val kvFruit: RDD[(Int, String)] = sc.parallelize(List((1, "apple"), (2, "orange"), (3, "banana"), (4, "grape")))
    val fruitMap: collection.Map[Int, String] = kvFruit.collectAsMap()
    //这里面在数据量小的时候可以使用下面的方式
    val valueRDD: RDD[Int] = sc.parallelize(Seq(2, 1,3, 4))
    valueRDD.map(x => fruitMap(x)).collect().foreach(println(_))
    println("="*100)

    //但是如果fruitMap水果种类特别多的,每一个rdd的Task都需要拉取副本,造成大量数据网络传输,建议使用广播变量
    //这里面需要使用Map的数据结构,因为Array(1,"Apple),需要将array转化为Map结构
    val broad: Broadcast[collection.Map[Int, String]] = sc.broadcast(kvFruit.collectAsMap())
    valueRDD.map(x => broad.value(x)).collect().foreach(println(_))

    sc.stop()
  }
}

Je suppose que tu aimes

Origine blog.csdn.net/m0_49834705/article/details/112731900
conseillé
Classement