Spark Core API实现一些简单的案例

本文介绍如何使用Spark Core API实现SequenceFile读取、窗口函数FIRST_VALUE/LAST_VALUE及二次排序等功能,涵盖具体代码实现与运行结果。

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

1 读取Sequence File

读取文本格式我们可以使用text files,那么读取Sequence File该怎么办呢?
当然官网给我们提供了另外一种方式,sequenceFile[K, V] 方法,其中k和v是文件中的键值和值类型。他们实现了Writable接口。

  • 准备数据
通过Hive创建一份Sequence File的数据
create table states_raw(code string, name string)
ROW FORMAT DELIMITED FIELDS TERMINATED BY " ";

load data local inpath "/home/hadoop/data/input.txt" overwrite into table states_raw;   

create table states_seq(code string, name string)
ROW FORMAT DELIMITED FIELDS TERMINATED BY " "
STORED AS SEQUENCEFILE;

insert into table states_seq select * from states_raw; 
  • 代码
import org.apache.hadoop.io.BytesWritable
import org.apache.spark.{SparkConf, SparkContext}


object ReadSequenceFile {
  def main(args: Array[String]): Unit = {
    //创建SparkConf
    val conf=new SparkConf().setAppName("ReadSequenceFile").setMaster("local[2]")
    //创建SparkContext
    val sparkContext=new SparkContext(conf)
    //读取sequence文件
    val seq_file=sparkContext.sequenceFile[BytesWritable,String]("hdfs://192.168.137.130:9000/user/hive/warehouse/states_seq")
    seq_file.collect().foreach(println);
    sparkContext.stop()
  }
}

这时候你会发现上面的代码是报错的,错误提示为:没有进行序列化

18/05/22 22:06:13 ERROR TaskSetManager: Task 0.0 in stage 0.0 (TID 0) had a not serializable result: org.apache.hadoop.io.BytesWritable
Serialization stack:
    - object not serializable (class: org.apache.hadoop.io.BytesWritable, value: )
    - field (class: scala.Tuple2, name: _1, type: class java.lang.Object)
    - object (class scala.Tuple2, (,hello java))
    - element of array (index: 0)
    - array (class [Lscala.Tuple2;, size 6); not retrying
18/05/22 22:06:13 INFO TaskSchedulerImpl: Removed TaskSet 0.0, whose tasks have all completed, from pool 
18/05/22 22:06:13 INFO TaskSchedulerImpl: Cancelling stage 0
18/05/22 22:06:13 INFO DAGScheduler: ResultStage 0 (collect at ReadSequenceFile.scala:17) failed in 0.938 s due to Job aborted due to stage failure: Task 0.0 in stage 0.0 (TID 0) had a not serializable result: org.apache.hadoop.io.BytesWritable

原因:对于Sequence File的存储格式是一种KV数据格式,Key和Value都是二进制变长的数据,key为空使用value 存放实际的值, 这样是为了避免MR 在执行map 阶段的排序过程。
上面的代码中val seq_file=sparkContext.sequenceFile[BytesWritable,String]("hdfs://192.168.137.130:9000/user/hive/warehouse/states_seq");这一句是没有问题的,问题出现在下面一句seq_file.collect().foreach(println);
- 修改

import org.apache.hadoop.io.BytesWritable
import org.apache.spark.{SparkConf, SparkContext}

object ReadSequenceFile {
  def main(args: Array[String]): Unit = {
    //创建SparkConf
    val conf=new SparkConf().setAppName("ReadSequenceFile").setMaster("local[2]")
    //创建SparkContext
    val sparkContext=new SparkContext(conf)
    //读取sequence文件
    val seq_file=sparkContext.sequenceFile[BytesWritable,String]("hdfs://192.168.137.130:9000/user/hive/warehouse/states_seq")

    //打印出key(把key转化为字节) value
    //seq_file.map(x=>(x._1.copyBytes(),x._2)).collect().foreach(println);

    //只取value,根据空格进行切分,读取切分后的值
    seq_file.map(x=> (x._2.split(" "))).map(x=>(x(0),x(1))).collect().foreach(println)
    sparkContext.stop()
  • 结果
(hello,java)
(hello,hadoop)
(hello,hive)
(hello,sqoop)
(hello,hdfs)
(hello,spark)

2 使用Spark Core API 实现窗口函数:FIRST_VALUE,LAST_VALUE

对于这个窗口函数不理解的同学可以参考这篇博客

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

object FirstValue {
  def main(args: Array[String]): Unit = {
    val conf = new SparkConf().setAppName("FirstValueApp").setMaster("local[2]")
    val sc = new SparkContext(conf)
    val data = sc.parallelize(List(
      ("A", "A1"),
      ("A", "A2"),
      ("A", "A3"),
      ("B", "B1"),
      ("B", "B2"),
      ("B", "B3"),
      ("C", "C1")
    ))
    //data.collect().foreach(println)
    /*首先进行分组,在进行排序,结果如下:
    (A,CompactBuffer(A1, A2, A3))
    (B,CompactBuffer(B1, B2, B3))
    (C,CompactBuffer(C1))
    但是这时候core中并没有直接实现可以拿到first value 。
    那我们要做的是拿到
    (A,List((A1,A1), (A2,A1), (A3,A1)))
    (B,List((B1,B1), (B2,B1), (B3,B1)))
    (C,List((C1,C1)))
    即,迭代出第一个元素即可
     */
    data.groupByKey().sortByKey()
        .map(x=>(x._1,firstValue(x._2)))
      .collect().foreach(println)

    //自定义一个方法
    //进来一个迭代器,输出一个firstvalue
    def firstValue(values: Iterable[String]) = {
      values.head
    }

    sc.stop()
  }
}

结果
(A,List((A1,A1), (A2,A1), (A3,A1)))
(B,List((B1,B1), (B2,B1), (B3,B1)))
(C,List((C1,C1)))
  • LAST_VALUE
package cn.zhangyu

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

/**
  * Created by grace on 2018/5/23.
  */
object LastValue {
  def main(args: Array[String]): Unit = {
    val conf = new SparkConf().setAppName("FirstValueApp").setMaster("local[2]")
    val sc = new SparkContext(conf)
    val data = sc.parallelize(List(
      ("A", "A1"),
      ("A", "A2"),
      ("A", "A3"),
      ("B", "B1"),
      ("B", "B2"),
      ("B", "B3"),
      ("C", "C1")
    ))
    //data.collect().foreach(println)
    /*首先进行分组,在进行排序,结果如下:
    (A,CompactBuffer(A1, A2, A3))
    (B,CompactBuffer(B1, B2, B3))
    (C,CompactBuffer(C1))
    但是这时候core中并没有直接实现可以拿到lastValue 。
    那我们要做的是拿到
    (A,List((A1,A3), (A2,A3), (A3,A3)))
    (B,List((B1,B3), (B2,B3), (B3,B3)))
    (C,List((C1,C1)))
    即,迭代最后一个元素即可
     */
    data.groupByKey().sortByKey()
      .map(x=>(x._1,lastValue(x._2)))
      .collect().foreach(println)

    //自定义一个方法
    //进来一个迭代器,输出一个lastValue
    def lastValue(values: Iterable[String]) = {
      for(value <- values)
        yield (value, values.last)
    }

    sc.stop()
  }
}

结果:
(A,List((A1,A3), (A2,A3), (A3,A3)))
(B,List((B1,B3), (B2,B3), (B3,B3)))
(C,List((C1,C1)))

3 使用Spark Core API实现二次排序

package cn.zhangyu
import org.apache.spark.{SparkConf, SparkContext}
/**
  * 使用Spark Core API实现二次排序
  *  1) 自定义排序的key, 要实现Ordered和Serializable接口
  *  2)将要排序的数据,映射成key为自定义排序的key,value就是原始的值
  *  3)按照业务逻辑实现compare方法
  *  4)使用sortByKey(false/true)算子按照自定义的key进行排序
  *  5)丢弃key,取value
  */
object SecondSort {
    def main(args: Array[String]) {
      val conf = new SparkConf().setAppName("FirstValueApp").setMaster("local[2]")
      val sc = new SparkContext(conf)

      val data = sc.textFile("E:/IdeaProjects/SparkCore/src/resource/sort.txt")
      /*
      sort.txt
      1,12
      3,4
      6,2
      12,30
      4,23
      7,33
      20,25
      6,9
      12,23
       */
      //data.collect().foreach(println)
      //切分
//      data.map(x=>{
//        x.split(",")
//        //new SecondSortKey(splits(0).trim.toLong,splits(1).trim.toLong)
//      }).collect().foreach(println)

      data.map(x => {
        val splits = x.split(",")
        //(key,value) 这里的key将(c1,c2)作为一个整体传给自定义的SecondSortKey方法如果c1不相等就按照c1排序,如果c1相等就按照c2排序,value就是(c1,c2)
        (new SecondSortKey(splits(0).trim.toLong, splits(1).trim.toLong), x)
      }).sortByKey().map(x => x._2)
        .collect().foreach(println)
      sc.stop()
  }

  // 将(c1,c2)作为一个整体,当做是SecondSortKey
  // 在scala中,第一个trait(接口)我们可以使用extends,如果还有其他trait,就用with
  //这里自定义一个SecondSortKey方法实现了Ordered,Ordered接口的类具备了比较的特性,要实现他的compare方法
  //这里的compare方法如果“this”对象比传递的对象(“that”)参数更小、相等或更大时,它返回一个负整数、0或正整数。
    class SecondSortKey(val first:Long,val second:Long) extends Ordered[SecondSortKey] with Serializable{
    override def compare(that: SecondSortKey): Int = {
      if(this.first!=that.first){
        (this.first-that.first).toInt
      }else{
        (this.second - that.second).toInt
      }
    }
  }


}


结果:
1,12
3,4
4,23
6,2
6,9
7,33
12,23
12,30
20,25

注意: Scala中的比较器Ordered与Ordering个人感觉就是java中的Comparable和Comparator。

  1. Scala提供两个特质(trait)Ordered与Ordering用于比较。其中,Ordered混入(mix)Java的Comparable接口,而Ordering则混入Comparator接口。
  2. 众所周知,在Java中实现Comparable接口的类,其对象具有了可比较性;
  3. 实现comparator接口的类,则提供一个外部比较器,用于比较两个对象。

Ordered与Ordering的区别与之相类似:
Ordered特质定义了相同类型间的比较方式,但这种内部比较方式是单一的;
Ordered则是提供比较器模板,可以自定义多种比较方式。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值