在Spark开发中,有时为了更好的效率,特别是涉及到关联操作的时候,对数据进行重新分区操作可以提高程序运行效率(很多时候效率的提升远远高于重新分区的消耗,所以进行重新分区还是很有价值的)。
在SparkSQL中,对数据重新分区主要有两个方法 repartition 和 coalesce ,下面将对两个方法比较

repartition

repartition 有三个重载的函数:

  • def repartition(numPartitions: Int): DataFrame 
 /**
* Returns a new [[DataFrame]] that has exactly `numPartitions` partitions.
* @group dfops
* @since 1.3.0
*/
def repartition(numPartitions: Int): DataFrame = withPlan {
Repartition(numPartitions, shuffle = true, logicalPlan)
}

此方法返回一个新的[[DataFrame]],该[[DataFrame]]具有确切的 'numpartition' 分区。

  • def repartition(partitionExprs: Column*): DataFrame 
 /**
* Returns a new [[DataFrame]] partitioned by the given partitioning expressions preserving
* the existing number of partitions. The resulting DataFrame is hash partitioned.
*
* This is the same operation as "DISTRIBUTE BY" in SQL (Hive QL).
*
* @group dfops
* @since 1.6.0
*/
@scala.annotation.varargs
def repartition(partitionExprs: Column*): DataFrame = withPlan {
RepartitionByExpression(partitionExprs.map(_.expr), logicalPlan, numPartitions = None)
}

此方法返回一个新的[[DataFrame]]分区,它由保留现有分区数量的给定分区表达式划分。得到的DataFrame是哈希分区的。

这与SQL (Hive QL)中的“distribution BY”操作相同。

  • def repartition(numPartitions: Int, partitionExprs: Column*): DataFrame
   /**
* Returns a new [[DataFrame]] partitioned by the given partitioning expressions into
* `numPartitions`. The resulting DataFrame is hash partitioned.
*
* This is the same operation as "DISTRIBUTE BY" in SQL (Hive QL).
*
* @group dfops
* @since 1.6.0
*/
@scala.annotation.varargs
def repartition(numPartitions: Int, partitionExprs: Column*): DataFrame = withPlan {
RepartitionByExpression(partitionExprs.map(_.expr), logicalPlan, Some(numPartitions))
}

此方法返回一个新的[[DataFrame]],由给定的分区表达式划分为 'numpartition' 。得到的DataFrame是哈希分区的。

这与SQL (Hive QL)中的“distribution BY”操作相同。

coalesce

  • coalesce(numPartitions: Int): DataFrame
   /**
* Returns a new [[DataFrame]] that has exactly `numPartitions` partitions.
* Similar to coalesce defined on an [[RDD]], this operation results in a narrow dependency, e.g.
* if you go from 1000 partitions to 100 partitions, there will not be a shuffle, instead each of
* the 100 new partitions will claim 10 of the current partitions.
* @group rdd
* @since 1.4.0
*/
def coalesce(numPartitions: Int): DataFrame = withPlan {
Repartition(numPartitions, shuffle = false, logicalPlan)
}

返回一个新的[[DataFrame]],该[[DataFrame]]具有确切的 'numpartition' 分区。类似于在[[RDD]]上定义的coalesce,这种操作会导致一个狭窄的依赖关系,例如:

如果从1000个分区到100个分区,就不会出现shuffle,而是100个新分区中的每一个都会声明10个当前分区。

反过来从100个分区到1000个分区,将会出现shuffle。

注:coalesce(numPartitions: Int): DataFrame    和 repartition(numPartitions: Int): DataFrame 底层调用的都是 class Repartition(numPartitions: Int, shuffle: Boolean, child: LogicalPlan)

 /**
* Returns a new RDD that has exactly `numPartitions` partitions. Differs from
* [[RepartitionByExpression]] as this method is called directly by DataFrame's, because the user
* asked for `coalesce` or `repartition`. [[RepartitionByExpression]] is used when the consumer
* of the output requires some specific ordering or distribution of the data.
*/
case class Repartition(numPartitions: Int, shuffle: Boolean, child: LogicalPlan)
extends UnaryNode {
override def output: Seq[Attribute] = child.output
}

返回一个新的RDD,该RDD恰好具有“numpartition”分区。与[[RepartitionByExpression]]不同的是,这个方法直接由DataFrame调用,因为用户需要' coalesce '或' repartition '。

当输出的使用者需要特定的数据排序或分布时使用[[RepartitionByExpression]]。(源码里面说的是RDD,但是返回类型写的是DataFrame,感觉没差)。

repartition(partitionExprs: Column*): DataFramerepartition(numPartitions: Int, partitionExprs: Column*): DataFrame 底层调用是

class RepartitionByExpression(partitionExpressions:Seq[Expression],child:LogicalPlan,numPartitions:Option[Int]=None) extends RedistributeData

 /**
* This method repartitions data using [[Expression]]s into `numPartitions`, and receives
* information about the number of partitions during execution. Used when a specific ordering or
* distribution is expected by the consumer of the query result. Use [[Repartition]] for RDD-like
* `coalesce` and `repartition`.
* If `numPartitions` is not specified, the number of partitions will be the number set by
* `spark.sql.shuffle.partitions`.
*/
case class RepartitionByExpression(
partitionExpressions: Seq[Expression],
child: LogicalPlan,
numPartitions: Option[Int] = None) extends RedistributeData {
numPartitions match {
case Some(n) => require(n > 0, "numPartitions must be greater than 0.")
case None => // Ok
}

该方法使用[[Expression]]将数据重新划分为 'numpartition',并在执行期间接收关于分区数量的信息。当用户期望某个特定的排序或分布时使用。使用[[Repartition]]用于类rdd的 'coalesce' 和 'Repartition'。

如果没有指定 'numpartition',那么分区的数量将由 "spark.sql.shuffle.partition" 设置。

使用示例

  • def repartition(numPartitions: Int): DataFrame 
 //    获取一个测试的DataFrame 里面包含一个user字段
val testDataFrame: DataFrame = readMysqlTable(sqlContext, "MYSQLTABLE", proPath)
// 获得10个分区的DataFrame
testDataFrame.repartition(10) 
  • def repartition(partitionExprs: Column*): DataFrame 
 //    获取一个测试的DataFrame 里面包含一个user字段
val testDataFrame: DataFrame = readMysqlTable(sqlContext, "MYSQLTABLE", proPath)
// 根据 user 字段进行分区,分区数量由 spark.sql.shuffle.partition 决定
testDataFrame.repartition($"user")
  • def repartition(numPartitions: Int, partitionExprs: Column*): DataFrame
 //    获取一个测试的DataFrame 里面包含一个user字段
val testDataFrame: DataFrame = readMysqlTable(sqlContext, "MYSQLTABLE", proPath)
// 根据 user 字段进行分区,将获得10个分区的DataFrame,此方法有时候在join的时候可以极大的提高效率,但是得注意出现数据倾斜的问题
testDataFrame.repartition(10,$"user") 
  • coalesce(numPartitions: Int): DataFrame
 val testDataFrame1: DataFrame = readMysqlTable(sqlContext, "MYSQLTABLE", proPath)
val testDataFrame2=testDataFrame1.repartition(10)
// 不会触发shuffle
testDataFrame2.coalesce(5)
// 触发shuffle 返回一个100分区的DataFrame
testDataFrame2.coalesce(100)  

至于分区的数据设定,得根据自己的实际情况来,多了浪费少了负优化。

现在的只是初步探讨,具体的底层代码实现,后续去研究一下。

此文为本人工作学习整理笔记,转载请注明出处!!!!!!

Spark源码系列:DataFrame repartition、coalesce 对比的更多相关文章

  1. Spark源码系列:RDD repartition、coalesce 对比

    在上一篇文章中 Spark源码系列:DataFrame repartition.coalesce 对比 对DataFrame的repartition.coalesce进行了对比,在这篇文章中,将会对R ...

  2. Spark源码系列(五)分布式缓存

    这一章想讲一下Spark的缓存是如何实现的.这个persist方法是在RDD里面的,所以我们直接打开RDD这个类. def persist(newLevel: StorageLevel): this. ...

  3. Spark源码系列(一)spark-submit提交作业过程

    前言 折腾了很久,终于开始学习Spark的源码了,第一篇我打算讲一下Spark作业的提交过程. 这个是Spark的App运行图,它通过一个Driver来和集群通信,集群负责作业的分配.今天我要讲的是如 ...

  4. Spark源码系列(九)Spark SQL初体验之解析过程详解

    好久没更新博客了,之前学了一些R语言和机器学习的内容,做了一些笔记,之后也会放到博客上面来给大家共享.一个月前就打算更新Spark Sql的内容了,因为一些别的事情耽误了,今天就简单写点,Spark1 ...

  5. Spark源码系列(八)Spark Streaming实例分析

    这一章要讲Spark Streaming,讲之前首先回顾下它的用法,具体用法请参照<Spark Streaming编程指南>. Example代码分析 val ssc = )); // 获 ...

  6. Spark源码系列(七)Spark on yarn具体实现

    本来不打算写的了,但是真的是闲来无事,整天看美剧也没啥意思.这一章打算讲一下Spark on yarn的实现,1.0.0里面已经是一个stable的版本了,可是1.0.1也出来了,离1.0.0发布才一 ...

  7. Spark源码系列(六)Shuffle的过程解析

    Spark大会上,所有的演讲嘉宾都认为shuffle是最影响性能的地方,但是又无可奈何.之前去百度面试hadoop的时候,也被问到了这个问题,直接回答了不知道. 这篇文章主要是沿着下面几个问题来开展: ...

  8. Spark源码系列(四)图解作业生命周期

    这一章我们探索了Spark作业的运行过程,但是没把整个过程描绘出来,好,跟着我走吧,let you know! 我们先回顾一下这个图,Driver Program是我们写的那个程序,它的核心是Spar ...

  9. Spark源码系列(三)作业运行过程

    作业执行 上一章讲了RDD的转换,但是没讲作业的运行,它和Driver Program的关系是啥,和RDD的关系是啥? 官方给的例子里面,一执行collect方法就能出结果,那我们就从collect开 ...

随机推荐

  1. FreeType使用的总结

    http://www.cppblog.com/liangairan/archive/2016/09/11/214270.html 这里说一下Freetype的关键点,比较基础的在很多文章已经有说明,这 ...

  2. Python随笔--对象

    组合的用法:

  3. spring security 学习

    1.默认登录   user  /df1fc617-bb94-494e-8adb-0234046bf092 取消校验 在启动类上添加下面的注解 @EnableAutoConfiguration(excl ...

  4. 文件防删除保护(miniifiter)

    0x01 思路(原理) 驱动层文件保护的思路是通过minifilter过滤文件删除相关的IRP,并将目标文件与被保护文件相比较,命中保护规则的话返回STATUS_ACCESS_DENIED拒绝访问:也 ...

  5. CrashHandler

    CrashHandler 全局Crash捕获处理

  6. java基础知识—类的方法

    1.定义类方法的语法: 访问修饰符 返回值类型 方法名(){ 方法体: } 2.方法名的规范: 1.必须以字母下划线·“—”或“$”开头 2.可以有数字,但不能以数字开头. 3.如果方法名是以多个单词 ...

  7. 【转】用opencv使摄像头在30fps下捕获1080p的数据

    原文:http://blog.sina.com.cn/s/blog_9b493e7b0102xvn6.html opencv可以捕获摄像头数据.如果要读高分辨率和高帧率,可以用如下的设置: captu ...

  8. [转载] Fiddler为所欲为第三篇 封包逆向必备知识[三]

    导语: 小A同学:会抓包有什么好学习的,不就用一个工具设置个wifi代{过}{滤}理就OK了嘛,还不是很多做不了.不如学习安卓逆向.didi科学家:不好意思,抓包可以为所欲为. 其实学习抓包,完完全全 ...

  9. java 中根据类的属性排序

    package edu.del; import java.util.ArrayList; import java.util.Collections; import java.util.List; im ...

  10. python day32--struct,文件上传下载

    一.struct模块 可以把要发送的数据长度转换成固定长度的字节 struct.pack('i',数据长度) struct.unpack('i',数据长度) 二.上传下载文件作业 server imp ...