Spark先分区再排序

处理数据时,比我们想对一个年级的所有语文考试成绩先按班级分类,再在每个班级里按成绩排名,最终每个班级的数据保存为一个文件,这就要用到spark分区加排序的技巧

数据为DF格式时

代码

 val spark  =SparkSession.builder().config(new SparkConf()).getOrCreate()
       val sc =spark.sparkContext
       val data = sc.parallelize(Array((100,2),(200,1),(300,3),(100,4),(200,4),(300,8) ,(200,5),(300,6),(100,5),(100,0),(200,6),(200,-1)))

       import spark.implicits._
       val DF_sort_partition =data.toDF("key","value")
         .sort(desc("value"))
         .write
         .partitionBy("key")
         .mode(SaveMode.Overwrite)
         .parquet("develop/wangdaopeng/partitionTest")

       val s1 =spark.read.parquet("develop/wangdaopeng/partitionTest/key=100").show()
       val s2 =spark.read.parquet("develop/wangdaopeng/partitionTest/key=200").show()
结果的保存形式

Spark先分区再排序_第1张图片
因为我们是根据"key"字段来保存,所以保存结果的目录是key=xx的形式,每个key对应一个分区

结果内容

key=100:
Spark先分区再排序_第2张图片
key=200:
Spark先分区再排序_第3张图片
结果完全符合预期

数据为RDD格式时

如果像DF格式那样写,是达不到预期的效果的,比如下列代码
先排序再分区

          data
         .sortBy(_._2)
         .partitionBy(new HashPartitioner(3))

或者先分区再排序

			data
           .partitionBy(new HashPartitioner(3))
           .sortBy(_._2)

结果都是不符合预期的
对于RDD,一种简单的先分区再再分区里进行排序的方法如下,先repartition,RDD的partitionBy默认都是根据key值来进行的(对于pair 对,就是第一个元素),mapPartitions 输入和返回的都是一个迭代器,排序的方法在于先把iterator转化为list 排序再以iterator的形式返回


   val res =data
          .partitionBy(new HashPartitioner(3))
          .mapPartitions{x=>
              x.toList.sortBy(_._2).toIterator
          }
          .saveAsTextFile(path)

结果
Spark先分区再排序_第4张图片

你可能感兴趣的:(Spark)