spark中实现自定义排序

排序的方式可以分为6中:

(1)使用一个自定义一个普通的类继承Ordered[User] with Serializable

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("CustomerSort1").setMaster("local[2]")
    val sc = new SparkContext(conf)
    //定义一个数组类型的值
    val user = Array("laoduan 30 99", "laozhao 29 9999", "laozhang 28 98", "laoyang 28 99")
    //转换成RDD的类型
    val lines = sc.parallelize(user)
    //将整个字符串切分为元组的形式
    val sorted: RDD[User] = lines.map(x => {
      val line = x.split(" ")
      val name = line(0)
      val age = line(1).toInt
      val face = line(2).toInt
      new User(name, age, face)
    })
    //实现自定义排序需要调用sortBy才可以自动调用自定义排序
    val r = sorted.sortBy(u=>u)
    println(r.collect().toBuffer)

  }
  class User(val name:String,val age:Int,val face:Int)extends Ordered[User] with Serializable{
    override def compare(that: User): Int = {
      if (this.face == that.face){
        this.age-that.age
      }else{
       - (this.face-that.face)
      }
    }
  override def toString: String = s"name :$name,age: $age,face:$face"
  }
}

(2)和上面的差不多只是new 的位置是不太一样的


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

object CustomSort2 {
  //排序规则:首先按照颜值的降序,如果颜值相等,再按照年龄的升序
  def main(args: Array[String]): Unit = {
    val conf = new SparkConf().setAppName("CustomSort2").setMaster("local[2]")
    val sc = new SparkContext(conf)
    val user = Array("laoduan 30 99", "laozhao 29 9999", "laozhang 28 98", "laoyang 28 99")
    val lines = sc.parallelize(user)
    val tpRdd=lines.map(x=>{
      val line = x.split(" ")
      val name = line(0)
      val age = line(1).toInt
      val face = line(2).toInt
     (name, age, face)
    })
    val sorted = tpRdd.sortBy(x=>new User1(x._2,x._3))
    sorted.foreach(println)
  }
  //这里定义的参数必须添加类型,传的参数只是自己需要比较的参数,没有重写toString()方法
  class User1(val age:Int,val face:Int)extends Ordered[User1] with Serializable {
    override def compare(that: User1): Int = {
      if (this.face == that.face){
        this.age-that.age
      }else{
        - (this.face-that.face)
      }
    }
  }
}

(3)使用了样例类的方式此时可以不用实现序列化,并且输出不能使用foreach,和并行度有关

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

object CustomSort3 {
  //排序规则:首先按照颜值的降序,如果颜值相等,再按照年龄的升序
  def main(args: Array[String]): Unit = {

    val conf = new SparkConf().setAppName("CustomSort3").setMaster("local[2]")
    val sc = new SparkContext(conf)
    val user = Array("laoduan 30 99", "laozhao 29 9999", "laozhang 28 98", "laoyang 28 99")
    val lines = sc.parallelize(user)
    val tpRdd=lines.map(x=>{
      val line = x.split(" ")
      val name = line(0)
      val age = line(1).toInt
      val face = line(2).toInt
      (name, age, face)
    })
    val sorted = tpRdd.sortBy(x=> Man(x._2,x._3))
   // sorted.foreach(println)
   // sc.stop()
    //不能使用foreach
    println(sorted.collect().toBuffer)
  }
  //这里定义的参数必须添加类型,传的参数只是自己需要比较的参数,没有重写toString()方法
  case class Man(age:Int,face:Int)extends Ordered[Man]  {
    override def compare(that: Man): Int = {
      if (this.face == that.face){
        this.age-that.age
      }else{
        - (this.face-that.face)
      }
    }
  }

}

(4)利用隐式转换的方式

利用隐式转换时,类可以不实现Ordered的特质,普通的类或者普通的样例类即可。
隐式转换支持,隐式方法,隐式函数,隐式的object和隐式的变量,
如果都同时存在,优先使用隐式的object,隐式方法和隐式函数中,会优先使用隐式函数。
隐式转换可以写在任意地方(当前对象中,外部的类中,外部的对象中),如果写在外部,需要导入到当前的对象中即可。



import org.apache.spark.rdd.RDD
import org.apache.spark.{SparkConf, SparkContext}
/**
  * 利用隐式转换时,类可以不实现Ordered的特质,普通的类或者普通的样例类即可。
    隐式转换支持,隐式方法,  隐式函数,  隐式的object  和隐式的变量,
如果都同时存在,优先使用隐式的object,隐式方法和隐式函数中,会优先使用隐式函数。
隐式转换可以写在任意地方(当前对象中,外部的类中,外部的对象中),如果写在外部,需要导入到当前的对象中即可。
  */
object CustomSort4 {
  def main(args: Array[String]): Unit = {
    val conf = new SparkConf().setAppName("CustomSort4").setMaster("local[*]")
    val sc = new SparkContext(conf)
    //排序规则:首先按照颜值的降序,如果颜值相等,再按照年龄的升序
    val users= Array("laoduan 30 99", "laozhao 29 9999", "laozhang 28 98", "laoyang 28 99")
    //将Driver端的数据并行化变成RDD
    val lines: RDD[String] = sc.parallelize(users)
    //切分整理数据
    val tpRDD: RDD[(String, Int, Int)] = lines.map(line => {
      val fields = line.split(" ")
      val name = fields(0)
      val age = fields(1).toInt
      val fv = fields(2).toInt
      (name, age, fv)
    })

    //隐式的object方式
      implicit object OrderingXiaoRou extends Ordering[XianRou]{
        override def compare(x: XianRou, y: XianRou): Int = {
          if(x.fv == y.fv) {
            x.age - y.age
          } else {
            y.fv - x.fv
          }
        }
      }
    // 如果类没有继承 Ordered 特质
    // 可以利用隐式转换  隐式方法  隐式函数  隐式值  隐式object都可以  implicit ord: Ordering[K]
    implicit def ordMethod(p: XianRou): Ordered[XianRou] = new Ordered[XianRou] {
      override def compare(that: XianRou): Int = {
        if (p.fv == that.fv) {
          -(p.age - that.age)
        } else {
          that.fv - p.fv
        }
      }
    }

    //利用隐式的函数方式
    implicit val ordFunc = (p: XianRou) => new Ordered[XianRou] {
      override def compare(that: XianRou): Int = {
        if (p.fv == that.fv) {
          -(p.age - that.age)
        } else {
          that.fv - p.fv
        }
      }
    }


    //排序(传入了一个排序规则,不会改变数据的格式,只会改变顺序)
    val sorted: RDD[(String, Int, Int)] = tpRDD.sortBy(tp => XianRou(tp._2, tp._3))
    println(sorted.collect().toBuffer)
    sc.stop()
  }
}
case class XianRou(age: Int, fv: Int)

(5)利用Ordering的on方法

无需借助任何的类或者对象

只需要利用Ordering特质的on方法即可。

import org.apache.spark.rdd.RDD
import org.apache.spark.{SparkConf, SparkContext}
object CustomSort5 {
  def main(args: Array[String]): Unit = {
    val conf = new SparkConf()
      .setMaster("local")
      .setAppName(this.getClass.getSimpleName)
    val sc = new SparkContext(conf)

    val users= Array("laoduan 30 99", "laozhao 29 9999", "laozhang 28 98", "laoyang 28 99")
    //将Driver端的数据并行化变成RDD
    val lines: RDD[String] = sc.parallelize(users)
    // 获得的数据类型是 元组
    val prdd = lines.map(t => {
      val strings = t.split(" ")
      val name = strings(0)
      val age = strings(1).toInt
      val fv = strings(2).toInt
      (name, age, fv)
    })
    implicit  val obj = Ordering[(Int,Int)].on[(String,Int,Int)](t=>(-t._3,t._2))

    val sortedrd: RDD[(String, Int, Int)] = prdd.sortBy(t => t)
    sortedrd.foreach(println)
  }
}

(6)利用元组封装排序条件

import org.apache.spark.rdd.RDD
import org.apache.spark.{SparkConf, SparkContext}
object CustomSort6 {
  def main(args: Array[String]): Unit = {
    val conf = new SparkConf().setAppName("CustomSort5").setMaster("local[*]")
    val sc = new SparkContext(conf)
    //排序规则:首先按照颜值的降序,如果颜值相等,再按照年龄的升序
    val users= Array("laoduan 30 99", "laozhao 29 9999", "laozhang 28 98", "laoyang 28 99")
    //将Driver端的数据并行化变成RDD
    val lines: RDD[String] = sc.parallelize(users)
    //切分整理数据
    val tpRDD: RDD[(String, Int, Int)] = lines.map(line => {
      val fields = line.split(" ")
      val name = fields(0)
      val age = fields(1).toInt
      val fv = fields(2).toInt
      (name, age, fv)})
    //充分利用元组的比较规则,元组的比较规则:先比第一,相等再比第二个
    val sorted: RDD[(String, Int, Int)] = tpRDD.sortBy(tp => (-tp._3, tp._2))
    println(sorted.collect().toBuffer)
    sc.stop()
  }
}

每天多努力一点

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值