在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. web前端框架之Vue hello world

    [博客园cnblogs笔者m-yb原创,转载请加本文博客链接,笔者github: https://github.com/mayangbo666,公众号aandb7,QQ群927113708] http ...

  2. flink基础教程读书笔记

    数据架构设计领域发生了重大的变化,基于流的处理是变化的核心. 分布式文件系统用来存储不经常更新的数据,他们也是大规模批量计算所以来的数据存储方式. 批处理架构(lambda架构)实现计数的方式:持续摄 ...

  3. SSL backend error when using OpenSSL pycurl install error

    centos7 pip install pycurl 错误 pip uninstall pycurl export PYCURL_SSL_LIBRARY=nss pip install pycurl ...

  4. jsp脚本的九个内置对象

    JSP脚本中包含9个内置对象, 这9个内置对象都是Servlet API 接口实例, 只是JSP规范对它们进行了默认初始化(由JSP 页面对应Servlet 的jspService()方法来创建这些实 ...

  5. participation remain wide

    Equal access to universities stagnates Image copyright Getty Images The most advantaged teens have t ...

  6. db2 常见错误以及解决方案[ErrorCode SQLState]

    操作数据库流程中,遇到许多疑问,很多都与SQL CODE和SQL State有关,现在把一个完整的SQLCODE和SQLState不正确信息和有关解释作以下说明,一来可以自己参考,对DB2不正确自行找 ...

  7. .net实现扫描二维码登录webqq群抓取qq群信息

    一.流程 1. //获得二维码的qrsig,cookie标志 2. //登录二维码获得二维码的状态,及最新的url 3. //登录此网址,获得Cookies 4.//cookies,筛选出skey信息 ...

  8. Windows 2008 asp.net 配置

    目录 1.     前言.. 32.     部署环境.. 32.1         服务器环境信息.. 33.     磁盘阵列配置.. 44.     安装操作系统.. 45.     安装软件. ...

  9. iOS常用算法

    1.冒泡排序 冒泡算法是一种基础的排序算法,这种算法会重复的比较数组中相邻的两个元素,如果一个元素比另一个元素大/小,那么就交换这两个元素的位置.重复一直比较到最后一个元素. 1.最差时间复杂度:O( ...

  10. JAVA对mongodb的基本操作

    public class test3 { //连接数据库(不需要验证,用于测试连接本地的mongodb) public static MongoDatabase getDatabase(String ...