Sparkの結合の広い依存関係はいつですか、狭い依存関係はいつですか

Sparkの結合の広い依存関係と狭い依存関係はいつですか
質問:
次のコードを参照してください1。2
つのprintステートメントの結果、対応する依存関係が広い依存関係であるか狭い依存関係であるか、およびこの結果はなぜですか
。2。結合操作はいつ広い依存関係であり、いつは狭い依存関係です。


import org.apache.spark.rdd.RDD
import org.apache.spark.{
    
    HashPartitioner, SparkConf, SparkContext}
object JoinDemo2 {
    
    
  def main(args: Array[String]): Unit = {
    
    
    val conf = new SparkConf().setAppName(this.getClass.getCanonicalName.init).setMaster("local[*]")
    val sc = new SparkContext(conf)
    sc.setLogLevel("WARN")
    val random = scala.util.Random
    val col1 = Range(1, 50).map(idx => (random.nextInt(10), s"user$idx"))
    val col2 = Array((0, "BJ"), (1, "SH"), (2, "GZ"), (3, "SZ"), (4, "TJ"), (5, "CQ"), (6, "HZ"), (7, "NJ"), (8, "WH"), (0,
      "CD"))
    val rdd1: RDD[(Int, String)] = sc.makeRDD(col1)
    val rdd2: RDD[(Int, String)] = sc.makeRDD(col2)
    val rdd3: RDD[(Int, (String, String))] = rdd1.join(rdd2)
    rdd3.count()
    println(rdd3.dependencies)
    val rdd4: RDD[(Int, (String, String))] = rdd1.partitionBy(new HashPartitioner(3)).join(rdd2.partitionBy(new
        HashPartitioner(3)))
    rdd4.count()
    println(rdd4.dependencies)
    Thread.sleep(10000000)
    sc.stop()
  }}

回答:1。2
つのprintステートメント:List(org.apache.spark.OneToOneDependency@63acf8f6) List(org.apache.spark.OneToOneDependency@d9a498)
ここに画像の説明を挿入
対応する依存関係:
rdd3は広い依存関係に対応し、rdd4は狭い依存関係に対応します。
理由:
1)
DAG図のwebUI参照してください。最初の結合が明確に分離されていることがわかります。前のもの。Satge。これは幅広い依存関係であることがわかります。2番目の結合であるpartitionByの後の結合は、個別にステージに分割されていないため、依存関係が狭いことを示しています。
rdd3 join
ここに画像の説明を挿入
rdd4 join
ここに画像の説明を挿入
2)コード分析:
a。最初はデフォルトの結合方法であり、ここではデフォルトのパーティショナーが使用されます

  /**
   * Return an RDD containing all pairs of elements with matching keys in `this` and `other`. Each
   * pair of elements will be returned as a (k, (v1, v2)) tuple, where (k, v1) is in `this` and
   * (k, v2) is in `other`. Performs a hash join across the cluster.
   */
  def join[W](other: RDD[(K, W)]): RDD[(K, (V, W))] = self.withScope {
    
    
    join(other, defaultPartitioner(self, other))
  }

b。デフォルトのパーティショナーは、最初の結合に対して、コンピューターコアの総数をパーティションの数として持つHas​​hPartitionerを返します。2番目の結合は、設定したHashPartitioner(パーティション番号3)を返します。

  def defaultPartitioner(rdd: RDD[_], others: RDD[_]*): Partitioner = {
    
    
    val rdds = (Seq(rdd) ++ others)
    val hasPartitioner = rdds.filter(_.partitioner.exists(_.numPartitions > 0))

    val hasMaxPartitioner: Option[RDD[_]] = if (hasPartitioner.nonEmpty) {
    
    
      Some(hasPartitioner.maxBy(_.partitions.length))
    } else {
    
    
      None
    }

    val defaultNumPartitions = if (rdd.context.conf.contains("spark.default.parallelism")) {
    
    
      rdd.context.defaultParallelism
    } else {
    
    
      rdds.map(_.partitions.length).max
    }

    // If the existing max partitioner is an eligible one, or its partitions number is larger
    // than the default number of partitions, use the existing partitioner.
    if (hasMaxPartitioner.nonEmpty && (isEligiblePartitioner(hasMaxPartitioner.get, rdds) ||
        defaultNumPartitions < hasMaxPartitioner.get.getNumPartitions)) {
    
    
      hasMaxPartitioner.get.partitioner.get
    } else {
    
    
      new HashPartitioner(defaultNumPartitions)
    }
  }

c。flatMapValuesが狭い依存関係であるjoinメソッドの実際の実行に移動します。したがって、広い依存関係がある場合は、cogroup演算子に含める必要があります。

  /**
   * Return an RDD containing all pairs of elements with matching keys in `this` and `other`. Each
   * pair of elements will be returned as a (k, (v1, v2)) tuple, where (k, v1) is in `this` and
   * (k, v2) is in `other`. Uses the given Partitioner to partition the output RDD.
   */
  def join[W](other: RDD[(K, W)], partitioner: Partitioner): RDD[(K, (V, W))] = self.withScope {
    
    
    this.cogroup(other, partitioner).flatMapValues( pair =>
      for (v <- pair._1.iterator; w <- pair._2.iterator) yield (v, w)
    )
  }

d。コグループメソッドを入力します。RDDとパーティショナーを結合する2つの必要性に応じて、コアはCoGroupedRDDです。最初の結合では、どちらのrddにもパーティショナーがないため、このステップでは、2つのrddが着信パーティショナーに基づいてシャッフルを実行する必要があるため、最初の結合は幅広い依存関係になります。この時点で、2番目の結合はゾーンに分割されており、再度シャッフルする必要はありません。だから2番目は狭い依存です

  /**
   * For each key k in `this` or `other`, return a resulting RDD that contains a tuple with the
   * list of values for that key in `this` as well as `other`.
   */
  def cogroup[W](other: RDD[(K, W)], partitioner: Partitioner)
      : RDD[(K, (Iterable[V], Iterable[W]))] = self.withScope {
    
    
    if (partitioner.isInstanceOf[HashPartitioner] && keyClass.isArray) {
    
    
      throw new SparkException("HashPartitioner cannot partition array keys.")
    }
    val cg = new CoGroupedRDD[K](Seq(self, other), partitioner)
    cg.mapValues {
    
     case Array(vs, w1s) =>
      (vs.asInstanceOf[Iterable[V]], w1s.asInstanceOf[Iterable[W]])
    }
  }

e。どちらもOneToOneDependencyを出力します。これは、CoGroupedRDDのgetDependenciesメソッドで、rddにパーティショナーがある場合、OneToOneDependency(rdd)を返すためです。

  override def getDependencies: Seq[Dependency[_]] = {
    
    
    rdds.map {
    
     rdd: RDD[_] =>
      if (rdd.partitioner == Some(part)) {
    
    
        logDebug("Adding one-to-one dependency with " + rdd)
        new OneToOneDependency(rdd)
      } else {
    
    
        logDebug("Adding shuffle dependency with " + rdd)
        new ShuffleDependency[K, Any, CoGroupCombiner](
          rdd.asInstanceOf[RDD[_ <: Product2[K, _]]], part, serializer)
      }
    }
  }
  1. いつ広い依存関係に参加し、いつ狭い依存関係に参加しますか?
    上記の分析から、結合される2つのテーブルにすでにパーティショナーがあり、パーティションの数が同じである場合、この時点で同じキーが同じパーティションにあることがわかります。狭い依存です。逆に、結合する必要のあるパーティションが2つのテーブルにない場合、またはパーティションの数が異なり、結合時にシャッフルが必要な場合は、大きな依存関係になります。

おすすめ

転載: blog.csdn.net/weixin_38813363/article/details/111868410