Spark源码解析排序算子sortBy和sortByKey存在未排序的情况

一.在使用中出现的问题

 1 package test
 2 
 3 import org.apache.log4j.{Level, Logger}
 4 import org.apache.spark.sql.SparkSession
 5 
 6 /**
 7   * Created by Administrator on 2019/12/17.
 8   */
 9 object TestZip {
10   /**
11     * 设置日志级别
12     */
13   Logger.getLogger("org").setLevel(Level.WARN)
14   def main(args: Array[String]) {
15     val spark = SparkSession.builder().master("local[2]").appName(s"${this.getClass.getSimpleName}").getOrCreate()
16     val sc = spark.sparkContext
17     val array_left = 1 until 4 //生成1到count的数组
18     val array_right = Array("工单", "电力", "展示")
19 
20     val result = array_left.zip(array_right)
21     val rdd = sc.parallelize(result).sortBy(_._1)
22     val rdd2 = sc.parallelize(result).sortByKey(true)
23 
24     rdd.foreach(println)
25     println("----------------")
26     rdd2.foreach(println)
27   }
28 }

二.执行结果

  

  从结果中可以看出,sortBy和sortByKey都没有实现排序的功能【虽然它们顺序已经改变】。这是怎么回事?

  

  具体原因下面我们从源码中进行分析!

三.源码分析

  

  在Spark的源码中,从RDD.scala代码中可以看出,sortBy底层调用的是sortByKey算子,在无升序降序的参数下【ascending】,默认为升序【true】,因此,我们只需要前往sortByKey中分析为什么没有实现排序功能即可。

  

  1.在OrderedRDDFunctions.scala中,可以看见sortByKey实现的具体细节,从注释中可以看出,排序基于key,在每个分区内部实现一个排序序列,注意,是每个分区内,下面我们去重置分区为1来检验一下是否有效!

  2.另外,注释也提到调用collect或者save也可以获取一个有序的序列,下面也一块去验证!

四.设置分区为1

  

  执行结果:

  

  由此可见,当设置分区数为1时【即合并所有分区为一个分区,显然之前的分区数不为1,查看存在多少分区数可以参考我的博客:https://www.cnblogs.com/yszd/p/10156231.html】,可以实现升序排序,当然降序也是可以的!

  

  

五.以collect为例进行验证

  

  

  备注:由此可见,调用collect也可以实现排序,但调用collect之后会返回一个Array,不再是RDD!

六.原因分析

  不管是repartition还是collect,其本质都是把各个executor中的数据汇总到master主节点中,是调用action算子,会存在repartition和shuffle操作。源码就很好的验证了这一点:

  

  在sortByKey中,会调用分区算子进行重新分区,与显式调用repartition有异曲同工之妙!

  

  而其中的ShuffledRDD会在shuffle执行过程中现在每个分区内进行排序,之后再进行整体的排序,以便提升排序性能,类似与归并排序算法!

posted @ 2019-12-24 11:33  云山之巅  阅读(1591)  评论(0编辑  收藏  举报