Learning Spark 笔记(七) -- 受益于分区的操作

原创 2016年08月30日 17:24:12

10 . 单元操作是怎样受益的?以reduceByKey为例子,reduceByKey是在本地归约后再发送到一个主机上再进行归约。如果父RDD是有分区信息的,那么就可能只会在本地归约了,而不会再跨网络发送到其它主机上。

二元操作是怎样受益于分区的?比如join(),至少会有一个RDD不会被shuffle。如果两个RDD有同样的partitioner,且被缓存在相同的机器上,则不会shuffle产生,比如

val b = a.mapValues(x=>x*x)
a.join(b)

因为mapValues()操作不会改变主键且不是shuffle操作,所以a和b的分区信息是一样的且在同一台机器上,二元操作join()不会有shuffle产生。

受分区信息影响的操作有

//一定会输出有Partitioner子RDD的操作
cogroup(),groupWith(), join(), leftOuterJoin(), rightOuterJoin(), groupByKey(), sort(), reduceByKey(),combineByKey(), partitionBy(),  
//如果有父RDD指定了Partitioner,则一定会输出有Partitioner的子RDD的操作
mapValues(), flatMapValues(), filter()

除了上面的这些操作,其它的操作都不会产生Partitioner。

最后三个操作
那么子RDD是怎样确定Partitioner和分区的呢?下面是Spark2.0.0的Partition.defaultPartitioner的源码,源码中定义了怎样确定子RDD的partitioner和分区数。

/**
   * Choose a partitioner to use for a cogroup-like operation between a number of RDDs.
   *
   * If any of the RDDs already has a partitioner, choose that one.
   *
   * Otherwise, we use a default HashPartitioner. For the number of partitions, if spark.default.parallelism is set, then we'll use the value from SparkContext defaultParallelism, otherwise we'll use the max number of upstream partitions.
   *
   * Unless spark.default.parallelism is set, the number of partitions will be the same as the number of partitions in the largest upstream RDD, as this should be least likely to cause out-of-memory errors.
   *
   * We use two method parameters (rdd, others) to enforce callers passing at least 1 RDD.
   */
  def defaultPartitioner(rdd: RDD[_], others: RDD[_]*): Partitioner = {
    val bySize = (Seq(rdd) ++ others).sortBy(_.partitions.length).reverse
    for (r <- bySize if r.partitioner.isDefined && r.partitioner.get.numPartitions > 0) {
      return r.partitioner.get
    }
    if (rdd.context.conf.contains("spark.default.parallelism")) {
      new HashPartitioner(rdd.context.defaultParallelism)
    } else {
      new HashPartitioner(bySize.head.partitions.length)
    }
  }

可以看到:
1. 父RDD中只有一个指定了Partitioner,则子RDD继承这个partitioner;
2. 父RDD中有若干个指定了Partitioner,则子RDD继承的是分区数最多的那个父RDD的Partitioner;
3. 如果父RDD中没有一个指定了Partitioner,则子RDD默认是HashPartitioner;
4. 在并行度没有指定的情况下,子RDD的分区数是和最大分区数的父RDD是一致的,如果指定了就优先使用指定的并行度。

利用partitionBy()操作优化程序的例子,PageRank:

// Assume that our neighbor list was saved as a Spark objectFile
val links = sc.objectFile[(String, Seq[String])]("links")
                //指定分区为哈希
                .partitionBy(new HashPartitioner(100))
                //持久化,默认为Storagelevel.MEMORY_ONLY                               
                .persist()                                                           
// Initialize each page's rank to 1.0; since we use mapValues, the resulting RDD will have the same partitioner as links
//mapValues不会改变分区信息
var ranks = links.mapValues(v => 1.0)                                             
// Run 10 iterations of PageRank
for (i <- 0 until 10) {
    //flatMap会改变分区信息,但却没有改变分区数100,所以contributions并没有持有links的RDD的分区信息
    val contributions = links.join(ranks).flatMap {                               
        case (pageId, (links, rank)) =>
            links.map(dest => (dest, rank / links.size))
    }
//  reduceByKey会产生默认的HashPartitioner分区,并且继承了之前的分区数,mapValues没有改变分区信息
ranks = contributions.reduceByKey((x, y) => x + y).mapValues(v => 0.15 + 0.85*v)
}
// Write out the final ranks
ranks.saveAsTextFile("ranks")

要最大化潜在的分区相关的优化,应该使用mapValues或者flatMapValues(),无论什么时候都不要改变元素的主键。

版权声明:本文为博主原创文章,未经博主允许不得转载。

影响Spark输出RDD分区的操作函数

1. 会影响到Spark输出RDD分区(partitioner)的操作cogroup, groupWith, join, leftOuterJoin, rightOuterJoin, groupByK...

影响到Spark输出RDD分区的操作函数

下面的操作会影响到Spark输出RDD分区(partitioner)的:   cogroup, groupWith, join, leftOuterJoin, rightOuterJoin, gro...
  • LW_GHY
  • LW_GHY
  • 2016年05月22日 21:00
  • 489

Learning Spark 笔记(六) -- 指定分区信息改善join()等的操作

9 . 默认情况下,join()操作会对两个RDD的主键做哈希以分区,通过网络将主键相同的元素发送到同一台机器上,然后根据相同的主键再进行连接。例子如下:val sc = new SparkConte...

spark RDD系列------2.HadoopRDD分区的创建以及计算

Spark经常需要从hdfs读取文件生成RDD,然后进行计算分析。这种从hdfs读取文件生成的RDD就是HadoopRDD。那么HadoopRDD的分区是怎么计算出来的?如果从hdfs读取的文件非常大...

Learning Spark——RDD常用操作

本文内容主要包括: 基本转换操作 键值对转换操作 行动操作 RDD支持两种操作:转换(Transformation)操作和行动(Action)操作。为什么会分为两种操作,这两种...
  • Trigl
  • Trigl
  • 2017年04月27日 17:33
  • 1522

分区的操作

  • 2014年05月07日 16:17
  • 9KB
  • 下载

Learning Spark (Python版) 学习笔记(二)----键值对、数据读取与保存、共享特性

 本来应该上周更新的,结果碰上五一,懒癌发作,就推迟了 = =。以后还是要按时完成任务。废话不多说,第四章-第六章主要讲了三个内容:键值对、数据读取与保存与Spark的两个共享特性(累加器和广播...

Learning Spark笔记7-数据分组、连接、排序数据

数据分组 一个常见的使用方式是按键分组我们的数据-例如,查看所有的客户订单。 如果我们的数据已经有key了,那么groupByKey()会使用key来分组我们的数据。在一个RDD上...

Learning Spark笔记10-PageRank

PageRank 基于Google的Larry Page命名的PageRank算法旨在根据有多少文档具有链接的方式为一组中的每个文档分配重要度(“等级”)。 它可以用于对网页进行排名,当然也...
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:Learning Spark 笔记(七) -- 受益于分区的操作
举报原因:
原因补充:

(最多只允许输入30个字)