Spark-分区器、文件读写与保存、累加器、广播变量

 分区器  

 文件读写与保存

 累加器

 广播变量


 分区器  

        Spark 目前支持 Hash 分区和 Range 分区,和用户自定义分区。Hash 分区为当前的默认 分区。分区器直接决定了 RDD 中分区的个数、RDD 中每条数据经过 Shuffle 后进入哪个分 区,进而决定了 Reduce 的个数。

  • 只有 Key-Value 类型的 RDD 才有分区器,非 Key-Value 类型的 RDD 分区的值是 None
  • 每个 RDD 的分区 ID 范围:0 ~ (numPartitions - 1),决定这个值是属于那个分区的。
object Spark_03 {
  def main(args: Array[String]): Unit = {
    val sparkConf = new SparkConf().setMaster("local[*]").setAppName("RDD")
    val sc = new SparkContext(sparkConf)
    val rdd: RDD[(String, String)] = sc.makeRDD(List(("a","aaa"),("b","bbb"),("c","ccc"),("d","ddd")))
    //创建自定义分区器对象
    val parRDD: RDD[(String, String)] = rdd.partitionBy( new MyPartitioner)
    parRDD.saveAsTextFile("output")

    //关闭环境
    sc.stop()
  }
}
//自定义分区器
  //继承Partitioner类
  //重写方法
  //
class MyPartitioner extends Partitioner {
  //分区数量
  override def numPartitions: Int = 3

  //返回数据分区索引(从0开始)
  override def getPartition(key: Any): Int = {
    key match { //设置分区
      case "aaa" => 0
      case "bbb" => 1
      case _ => 2
    }
  }
}

 

 文件读写与保存

        Spark 的数据读取及数据保存可以从两个维度来作区分:文件格式以及文件系统。 文件格式分为:text 文件、csv 文件、sequence 文件以及 Object 文件; 文件系统分为:本地文件系统、HDFS、HBASE 以及数据库。

text 文件

// 读取输入文件
val inputRDD: RDD[String] = sc.textFile("input/1.txt")
// 保存数据
inputRDD.saveAsTextFile("output")

sequence 文件

        SequenceFile 文件是 Hadoop 用来存储二进制形式的 key-value 对而设计的一种平面文件(Flat File)。在 SparkContext 中,可以调用 sequenceFile[keyClass, valueClass](path)。

// 保存数据为 SequenceFile
dataRDD.saveAsSequenceFile("output")
// 读取 SequenceFile 文件
sc.sequenceFile[Int,Int]("output").collect().foreach(println)

object 对象文件 

         对象文件是将对象序列化后保存的文件,采用 Java 的序列化机制。可以通过 objectFile[T: ClassTag](path)函数接收一个路径,读取对象文件,返回对应的 RDD,也可以通过调用 saveAsObjectFile()实现对对象文件的输出。因为是序列化所以要指定类型。

// 保存数据
dataRDD.saveAsObjectFile("output")
// 读取数据
sc.objectFile[Int]("output").collect().foreach(println)

 累加器

        累加器用来把 Executor 端变量信息聚合到 Driver 端。在 Driver 程序中定义的变量,在 Executor 端的每个 Task 都会得到这个变量的一份新的副本,每个 task 更新这些副本的值后, 传回 Driver 端进行 merge(合并)。

def main(args: Array[String]): Unit = {
    val sparkConf = new SparkConf().setMaster("local[*]").setAppName("RDD")
    val sc = new SparkContext(sparkConf)
    val rdd: RDD[Int] = sc.makeRDD(List(1,2,3,4,5,6))
    //获取系统累加器
    val sum: LongAccumulator = sc.longAccumulator("sum")
    //进行累加
    rdd.foreach(
      i => {
        //使用累加器
        sum.add(i)
      }
    )
    //获取累加器的值
    println(sum.value)

    sc.stop()
  }

自定义累加器

object Io {
  def main(args: Array[String]): Unit = {
    val sparkConf = new SparkConf().setMaster("local[*]").setAppName("RDD")
    val sc = new SparkContext(sparkConf)
    val rdd: RDD[String] = sc.makeRDD(List("word hello","spark java","hello java"))
    //创建累加器对象
    val accumulator = new MyAccumulator
    //向spark进行注册
    sc.register(accumulator,"wordCount")
    rdd.foreach(
      i => {
        //数据累加
        accumulator.add(i)
      }
    )
    //获得累加器的累加结果
    sc.stop()
    println(accumulator.value)
  }
}
//自定义累加器 :实现wordCount功能
//继承AccumulatorV2 再定义泛型 IN OUT
//重写方法
class MyAccumulator extends AccumulatorV2[String, mutable.Map[String,Long]]{
  private var wcMp = mutable.Map[String,Long]()

  //判断是否为初始状态
  override def isZero: Boolean = {
    wcMp.isEmpty //为空则是初始状态
  }

  override def copy(): AccumulatorV2[String, mutable.Map[String, Long]] = {
    new MyAccumulator()
  }
  //重置累加器
  override def reset(): Unit = {
    wcMp.clear() //清空
  }
  //获取累加器计算值
  override def add(word: String): Unit = {
    val newC= wcMp.getOrElse(word, 0L) + 1
    wcMp.update(word,newC)
  }

  //合并累加器
  override def merge(other: AccumulatorV2[String, mutable.Map[String, Long]]): Unit = {
    val map1 = this.wcMp
    val map2 = other.value

    map2.foreach{
      case (word, count) => {
        val newC: Long = map1.getOrElse(word,0L)+count
        map1.update(word,newC)
      }
    }
  }
  //累加器结果
  override def value: mutable.Map[String, Long] = {
    wcMp
  }
}

 广播变量

        广播变量用来高效分发较大的对象。向所有工作节点发送一个较大的只读值,以供一个 或多个 Spark 操作使用。比如,如果你的应用需要向所有节点发送一个较大的只读查询表, 广播变量用起来都很顺手。在多个并行操作中使用同一个变量,但是 Spark 会为每个任务 分别发送。

def main(args: Array[String]): Unit = {
    val sparkConf = new SparkConf().setMaster("local[*]").setAppName("RDD")
    val sc = new SparkContext(sparkConf)
    val rdd1= sc.makeRDD(List(("a",1),("b",2),("c",3)))

    val map = mutable.Map(("a",4),("b",5),("c",6))
    //join会导致数据量呈几何增长,并且会影响shuffle的性能,不推荐使用
    //rdd1.join(rdd2)
    rdd1.map {
      case (w, c) => {
        val l: Int = map.getOrElse(w,0)
        (w,(c,l))
      }
    }.collect().foreach(println)

    sc.stop()
  }
  def main(args: Array[String]): Unit = {
    val sparkConf = new SparkConf().setMaster("local[*]").setAppName("RDD")
    val sc = new SparkContext(sparkConf)
    val rdd1= sc.makeRDD(List(("a",1),("b",2),("c",3)))

    val map = mutable.Map(("a",4),("b",5),("c",6))
    //封装广播变量
    val bc: Broadcast[mutable.Map[String, Int]] = sc.broadcast(map)

    rdd1.map{
      case(w,c) => {
        val i: Int = bc.value.getOrElse(w,0)
        (w,(c,i))
      }
    }.collect().foreach(println)
    
    sc.stop()
  }

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

open_test01

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值