Spark自定义排序/分区

本文介绍了在Spark中如何进行自定义排序,包括两种方式:一是继承Ordering或Ordered并实现Serializable接口;二是通过隐式转换。同时,文章探讨了Hadoop的HashPartitioner策略,以及如何通过自定义分区类(extends Partitioner)来控制数据分布,以避免Hash碰撞并调整Reducer数量以优化性能。

Spark简单应用

自定义排序

  有两种方式:【1】定义一个类,继承Ordering或者Ordered,注意该类还要with Serializable接口,因为比较的时候可能要shuffle通过网络传输,因此必须是可序列化的【2】通过隐式转换的方式

//方式一
case class Men(val name:String,val faceValue:Int,val age:Int)extends Serializable{
  override def toString:String=s"[name:$name,fv:$faceValue,age:$age]"
}
object Context {
  implicit object MenOrdering extends Ordering[Men]{
    override def compare(x: Men, y: Men): Int = {
      if(x.faceValue>y.faceValue) 1
      else if(x.faceValue==y.faceValue){
        if(x.age>y.age)-1 else 1
      }else -1
    }
  }
}

//方式二
case class Men(val name:String,val faceValue:Int,val age:Int)extends Ordered[Men] with Serializable{
  override def compare(that: Men): Int = {
    if(this.faceValue==that.faceValue){
      that.age-this.age
    }else{
      this.faceValue-that.faceValue
    }
  }
}

object Test {
  def main(args:Array[String]): Unit ={
    val conf=new SparkConf().setAppName("Test").setMaster("local[2]")
    val sc=new SparkContext(conf)
    val rdd=sc.parallelize(List(("xiaoming",90,28,1),("zhagnsan",90,27,2)))
    //import Context._
    val result=rdd.sortBy(y=>Men(t._2,t._3),false).collect()
    sc.stop()
  }
}

自定义分区

  Hadoop的Partitioner策略:(K.hashcode&Integer.max)%(reducer number)。HashPartitioner相同Key的数据一定在同一个Reducer中,一个Reducer中只有一个Key,可能出现Hash碰撞,解决的方式把Reducer的数量增大,则Hash碰撞的概率会减小。自定义分区需要extends Partitioner,重写两个方法:一个是numPartitions返回分区的数量,一个是getPartition。

//分区器:决定数据分到哪个分区中
class MyPartitioner(ins:Array[String]) extends Partitioner{
  val parMap=new mutable.HashMap[String,Int]()
  var count=0
  for(i<-ins){
    parMap+=(i->count)
    count+=1
  }
  override def numPartitions:Int=ins.length
  override def getPartition(key:Any):Int={
    parMap.getOrElse(key.toString,0)
  }
}

object Test {
  def main(args:Array[String]){
    val conf=new SparkConf().setAppName("Test").setMaster("local[2]")
    val sc=new SparkContext(conf)
    //rdd1将数据切分,元组中放的是(URL,1)
    val rdd1=sc.textFile("c://Log.log").map(line=>{
      val f=line.split("\t")
      (f(1),1)
    })
    val rdd2=rdd1.reduceByKey(_+_)
    val rdd3=rdd2.map(t=>{
      val url=t._1
      val host=new URL(url).getHost
      (host,url,t._2)
    })
    val ints=rdd3.map(_._1).distinct().collect()
    val hostPartitioner=new MyPartitioner(ints)
    val rdd4=rdd3.partitionBy(hostPartitioner).mapPartitions(it=>{
      it.toList.sortBy(_._2._2).reverse.take(2).iterator
    })
    rdd4.saveAsTextFile("c://out")
  }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值