Spark自定义对象排序及自定义序列化

一、目标对象添加隐式转换函数的方式实现自定义排序

object MySort{
  //为student类添加隐式转换函数
  implicit val stuOrdering = new Ordering[student]{
    override def compare(x: student, y: student) = {
      //自定义排序格式为:默认按年龄升序排序,当年龄相同时,按分数降序排序
      if(x.age != y.age){
        x.age - y.age
      }else{
        y.score - x.score
      }
    }
  }
}
 
/**
  * 隐式转换函数实现自定义排序
  */
object CustomSort1{
  def main(args: Array[String]): Unit = {
    //1.创建配置对象
    val conf = new SparkConf().setAppName("sort1").setMaster("local[2]");
    //2.创建集群入口类对象
    val sc = new SparkContext(conf);
 
    //3.并行化的方式生成rdd
    val rdd = sc.parallelize(Array(("tom",24,92),("ko",24,97),("mark",28,88),("jack",18,86)))
 
    //4.对数据进行排序
    //引入隐式转换函数
    import MySort.stuOrdering
    val resRdd = rdd.sortBy(x => student(x._1,x._2.toInt,x._3.toInt))
 
    //5.打印排序后的结果数据
    println(resRdd.collect().toBuffer)
 
 
  }
}
//学生类
case class student(name:String,age:Int,score:Int)

二、目标对象实现Ordered特质的方式实现自定义排序

object CustomSort2{
  def main(args: Array[String]): Unit = {
    //1.创建配置对象
    val conf = new SparkConf().setAppName("sort2").setMaster("local[2]");
    //2.创建集群入口类对象
    val sc = new SparkContext(conf);
 
    //3.并行化的方式生成rdd
    val rdd = sc.parallelize(Array(("tom",24,92),("ko",24,97),("mark",28,88),("jack",18,86)))
 
    //4.对数据进行排序
    val resRdd = rdd.sortBy(x => student2(x._1,x._2.toInt,x._3.toInt))
 
    //5.打印排序后的结果数据
    println(resRdd.collect().toBuffer)
 
  }
}
 
case class student2(name:String,age:Int,score:Int) extends Ordered[student2]{
 
  override def compare(that: student2): Int = {
    if(this.age != that.age){
      this.age - that.age
    }else{
      that.score - this.score
    }
  }
}

 

三、其他序列化

package com.fuge.bigdata.datahub.analysis

import java.io.{DataInput, DataOutput}

import com.fuge.bigdata.tools.common.utils.SparkUtils
import org.apache.hadoop.io.{NullWritable, WritableComparable}
import org.apache.spark.SparkContext

/**
  * Created by chen xiang on 18-6-13.
  * 一个使用SequenceFile进行存储读取的使用示例
  */
object SequenceFileUsage {
  def main(args: Array[String]): Unit = {

    require(args.length == 1)
    // 构建SparkContext对象,封装过,单独运行,自行修改后定义
    val sc = new SparkContext(SparkUtils.getSparkConf("SequenceFileUsage"))

    // 获取路径参数
    val path = args(0).trim

    // 定义测试数据
    val studentList = List(Student("01", "abc"), Student("02", "baby"), Student("03", "xiang"))

    // 序列化测试数据到RDD,并写入到bos
    sc.parallelize(studentList)
      .repartition(1)
      // 以NullWritable 为key,构建kv结构.SequenceFile需要kv结构才能存储,NullWritable不占存储
      .map(NullWritable.get() -> _)
// 压缩参数可选用
      .saveAsSequenceFile(s"$path", Option(classOf[GzipCodec]))

    // 读取刚才写入的数据
    val studentRdd = sc.sequenceFile(s"$path/part-*", classOf[NullWritable], classOf[Student])
      .map {
        // 读取数据,并且重新赋值对象
        case (_, y) => Student(y.id, y.name)
      }
      .persist()

    studentRdd
      .foreach(x => println("count: " + x.id + "\t" + x.name))
  }
}

case class Student(var id: String, var name: String) extends WritableComparable[Student] {
  /**
    * 重写无参构造函数,用于反序列化时的反射操作
    */
  def this() {
    this("", "")
  }

  /**
    * 继承Comparable接口需要实现的方法,用于比较两个对象的大小
    */
  override def compareTo(o: Student): Int = {
    var cmp = id compareTo o.id
    if (cmp == 0) {
      cmp = name compareTo o.name
    }
    cmp
  }

  /**
    * 继承Writable接口需要实现的方法-反序列化读取结果,并且赋值到对象字段
    * 注意要和write的顺序一致
    */
  override def readFields(in: DataInput): Unit = {
    name = in.readUTF()
    id = in.readUTF()
    println("count: " + "\t id = " + id + "\t name = " + name)
  }

  /**
    * 继承Writable接口需要实现的方法-序列化写操作,将对象字段值写入序列化
    * 注意要和readFields的顺序一致
    */
  override def write(out: DataOutput): Unit = {
    out.writeUTF(id)
    out.writeUTF(name)
  }
}

补充:

1. 自定义的类需要进行序列化,必须都要实现Writable(或者直接实现Seriable,就不用重写了),一般情况下采用实现WritableComparable的方式,并且实现comparaTo,readFields, write方法,并且提供一个无参构造函数

2. readFields和write方法,里面字段的顺序要保持一致

3. 遇到集合类型,序列化时需要先将集合长度写进去,然后再挨个写集合数据

4. 遇到集合类型,反序列化时需要先读取集合的长度,然后接收数据,如果集合数据类型是自定义类型,还需要先实例化一个无参构造,然后赋值。

5. SequenceFile需要使用KV结构才能调用存储,可以使用一个NullWritable来占位,上诉例子中的K值就是使用的NullWritable进行的

6. sequenceFile序列化后占用的存储空间比较大,有需要的话,可以在存储的时候加上压缩算法,具体使用方式可以见上诉的例子

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值