Spark实现自定义排序

本文介绍了Spark中实现自定义排序的六种方法,包括创建类并重写compare方法、提供排序规则、使用case class、定义SortRules继承ordering、利用元组排序特性以及巧妙运用元组进行排序。通过这些方法,可以灵活地对数据进行复杂排序操作。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

第一种排序方法,比如有数据“name,age,颜值”,我们想按照颜值降序,颜值相同按照年龄升序排。

思路:写个类,将切分出来的数据放入到这个类中,重写这个类的compare方法,用这个类调用sortBy方法。 

package com.thy.d20190417

import org.apache.spark.rdd.RDD
import org.apache.spark.{SparkConf, SparkContext}
/**
  * 实现自定义排序
  */
object CustomSort1 {
  def main(args: Array[String]): Unit = {
    val conf = new SparkConf().setAppName("IpLocation").setMaster("local[*]")
    val sc: SparkContext = new SparkContext(conf)
    //排序规则,先按颜值降序,相等再按年龄升序
    val users=Array("laoduan 30 99","laozhao 29 9999", "laozhang 28 98", "laoyang 28 99")
    //将driver的数据并行化变成 RDD
    val lines  = sc.parallelize(users)
    //切分整理数据,将需要的数据切分出来,放到一个类中,
    //这个类继承ordered,然后重写compare,这个类在调用相应的排序方法的时候就会执行重写后的排序规则
    val userRDD: RDD[User] = lines.map(line => {
      val fields: Array[String] = line.split(" ")
      val name: String = fields(0)
      val age: Int = fields(1).toInt
      val fv: Int = fields(2).toInt
      new User(name, age, fv)
    })
    //u => u表示不传入排序规则,即会调用这个类重写的排序规则
    val sorted: RDD[User] = userRDD.sortBy(u => u)
    println(sorted.collect().toBuffer)
  }

  class User(val name:String,val age:Int,val fv:Int)extends Ordered[User] with Serializable {
    override def compare(that: User): Int = {
      if(this.fv == that.fv){
        this.age - that.age // 按照age升序
      }else{
        -(this.fv - that.fv) // 按照fv降序
      }
    }
    override def toString: String = s"name:$name,age:$age,facavalue:$fv"
  }
}

第二种方式:传入一个排序规则,不必将切分后的数据放入到一个类中,然后重写他的compare方法。

package com.thy.d20190417

import org.apache.spark.rdd.RDD
import org.apache.spark.{SparkConf, SparkContext}

object CustomSort2 {
  def main(args: Array[String]): Unit = {
    val conf = new SparkConf().setAppName("IpLocation").setMaster("local[*]")
    val sc: SparkContext = new SparkContext(conf)
    val users = Array("nanyang 25 99","thy 26 9999", "mingming 28 98", "wazi 22 99")
    val lines: RDD[String] = sc.parallelize(users)
    val tpRDD: RDD[(String, Int, Int)] = lines.map(line => {
      val fields: Array[String] = line.split(" ")
      val name: String = fields(0)
      val age: Int = fields(1).toInt
      val fv: Int = fields(2).toInt
      (name, age, fv)
    })
    // 传入一个排序规则,不改变数据格式,只改变顺序
    val sorted: RDD[(String, Int, Int)] = tpRDD.sortBy(tp => new MySort(tp._2,tp._3))
    println(sorted.collect().toBuffer)
    sc.stop()
  }
  //排序规则,将age和fv两个排序用到的属性传入,然后进行重写compare方法,当调用sortBy时,new一个本规则传入相应比较属性即可实现排序。
  class MySort(val age:Int,val fv:Int)extends Ordered[MySort] with Serializable {
    override def compare(that: MySort): Int = {
      if(this.fv == that.fv){
        this.age - that.age
      }else{
        -(this.fv - that.fv)
      }
    }
  }
}

 

第三种方式:使用case class。 case class与class区别:https://mp.youkuaiyun.com/postedit/89355621

package com.thy.d20190417

import org.apache.spark.rdd.RDD
import org.apache.spark.{SparkConf, SparkContext}

object CustomSort3 {
  def main(args: Array[String]): Unit = {
   
    /**
        此段代码同上 tpRDD为:(name,age,fv)
      */
    
    val sorted: RDD[(String, Int, Int)] = tpRDD.sortBy(tp => MySort(tp._2,tp._3))
    println(sorted.collect().toBuffer)
  }
  //case class 默认实现了序列化,不用在 with seria...
  case  class MySort(age:Int,fv:Int) extends Ordered[MySort]{
    override def compare(that: MySort): Int = {
      if(this.fv == that.fv){
        this.age - that.age
      }else{
        -(this.fv - that.fv)
      }
    }
  }
}

第四种方式:单独写个SortRules.scala,继承ordering,重写比较规则。排序时import SortRules.类,

package com.thy.d20190417

import com.thy.d20190417.CustomSort4.MySort2

object SortRules {
  implicit object  OrderingMySort extends Ordering[MySort2]{
    override def compare(x: MySort2, y: MySort2): Int = {
      if(x.fv == y.fv){
        x.age - y.age
      }else{
        -(x.fv - y.fv)
      }
    }
  }
}

//---------------------------------------------------------------------------------------

package com.thy.d20190417

import org.apache.spark.{SparkConf, SparkContext}
import org.apache.spark.rdd.RDD

object CustomSort4 {
  def main(args: Array[String]): Unit = {
      /**
        此段代码同上 tpRDD为:(name,age,fv)
      */
    import SortRules.OrderingMySort
    val sorted: RDD[(String, Int, Int)] = tpRDD.sortBy(tp => MySort2(tp._2,tp._3))
    println(sorted.collect().toBuffer)
    sc.stop()
  }
  case class MySort2(age:Int, fv: Int)
}


第五种方式:仅需要排序时,利用元组的排序特性即可

    //先降序比较fv,在升序比较age
    val sorted: RDD[(String, Int, Int)] = tpRDD.sortBy(tp => (-tp._3,tp._2))
    /**
        其他代码同上
    */

第六种:充分利用元组排序


//充分利用元组的比较规则,元组的比较规则:先比第一,相等再比第二个
    //比较前的数据格式
    //on[(String,Int,Int)]
    //最终比较的数据格式
    //Ordering[(Int,Int)]
    implicit val rules: Ordering[(String, Int, Int)] = Ordering[(Int,Int)].on[(String,Int,Int)](t => (-t._3,t._2))
    val sorted: RDD[(String, Int, Int)] = tpRDD.sortBy(tp =>tp)

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值