Spark累加器与广播变量以及初学SparkSQL

累加器:

目录

累加器:

广播变量

SparkSQL

DataFrame

DataSet

RDD,DF,DS直接的转换

自定义聚合函数

SparkSession:


为什么要使用累加器:在spark中如果不定义一个累加器在使用到累加计算方式时,因为task无法改变原始的变量,而在使用了累加器器后就可以对全局变量进行改写,所以累加器又称为全局可写变量

图解

使用方式:

object Spark_leijia {
  def main(args: Array[String]): Unit = {
    val conf = new SparkConf().setMaster("local").setAppName("word")
    val sc = new SparkContext(conf)
    val dataRDD = sc.makeRDD(List(1, 2, 3, 4), 2)
    //累加器共享变量
      //创建累加器对象
    val accumulator = sc.longAccumulator
    var sum=0;
    dataRDD.foreach{
      case  i =>{
        //执行累加功能
        accumulator.add(i)
      }
    }
    println("sum="+accumulator.value)
  }
}

注意点:累加器虽然又叫全局只写变量,但是他一样可读,只是用的最多是写的操作

广播变量

为什么使用广播变量:因为spark的变量是存在独立副本的,然后进行发送时Driver会对每一个task都进行分发一份,在task过多的时候会消耗大量的系统资源,所以出现了广播变量,广播变量也称为全局可读变量

图解

广播变量的使用

//定义广播变量
val a = 3
val broadcast = sc.broadcast(a)
//还原
val c = broadcast.value

注意点:广播变量与他的另一个名字一样一旦定义就只能进行读的操作无法改写

SparkSQL

什么是SpqrkSQL:Spark是一个类似于HIve的一种SQL都是为了替代MapReduce而诞生的,它提供了2个编程抽象:DataFrame和DataSet,并且作为分布式SQL查询引擎的作用

优点:易整合,统一的数据访问方式,兼容Hive,标准的数据连接

DataFrame

dataFrame是一个使用RDD为底层编写的分布式数据容器,相较于RDD来说他增加了数据的结构,类似于二维表格与hive类似。

dataFrame的使用:

df在构建的时候,需要对RDD的数据通过map来添加数据结构,或者直接读取有数据结构的文件如:json文件

 val conf = new SparkConf().setMaster("local[*]").setAppName("Spark_Sql1")
    val session = new SparkSession.Builder().config(conf).getOrCreate()
    //读取数据构建dataFrame
    val frame = session.read.json("D:\\spark-class\\in\\user.json")
    //采用sql的语法访问数据
    //将dataFram转换为一张表
    frame.createOrReplaceTempView("xxx");
    session.sql("select * from xxx").show
    //frame.show()
    session.stop()

DataSet

DataSet与Df非常类似但是,DS在DF的基础上添加了数据的类型,这样可以将数据当成一个对象来进行查询。

DS的使用DS的使用跟DF类似,不过创建时需要指定数据的类型,可以通过一个样例类来进行创建

RDD,DF,DS直接的转换

这三者的转换都是通过特定的函数添加或者去掉数据类型,数据结构来进行转换的

object Spark_SQL2 {
  def main(args: Array[String]): Unit = {
    val conf = new SparkConf().setMaster("local[*]").setAppName("Spark_Sql1")
    val session = new SparkSession.Builder().config(conf).getOrCreate()
    //装换前需要引入隐式转换规则
    //将RDD转换为DF
    val listRDD = session.sparkContext.makeRDD(List((1, "zhangsan", 21), (2, "lisi", 24)))
    import session.implicits._
    val dataFrame = listRDD.toDF("id", "name", "age")
    //DF转换为DS
    val dataSet = dataFrame.as[User]
    //DS转换为DF
    val dataFrame1 = dataSet.toDF()
    //DF转换为RDD
    val rdd = dataFrame1.rdd
    rdd.foreach(row =>{
      println(row.getString(1))
    })




  }

  /**
   * 样例类
   */
  case  class User(id:Int ,name:String,age:Int)
}
 def main(args: Array[String]): Unit = {
    val conf = new SparkConf().setMaster("local[*]").setAppName("word")
    val session = new SparkSession.Builder().config(conf).getOrCreate()
    import  session.implicits._
    //创建RDD
    val listRDD = session.sparkContext.makeRDD(List((1, "zhangsan", 21), (2, "lisi", 24)))
    //RDD转换为DS
    val userRDD = listRDD.map {
      case (id,name,age) => {
        User(id, name, age)
      }
    }
    userRDD.toDS().show()

  }

  /**
   * 样例类
   */
  case  class User(id:Int ,name:String,age:Int)

自定义聚合函数

弱类型:没有规定数据类型

object Spark_SQL4 {
  def main(args: Array[String]): Unit = {
    val conf = new SparkConf().setMaster("local[*]").setAppName("word")
    val session = new SparkSession.Builder().config(conf).getOrCreate()
    import session.implicits._
    //创建RDD
    val listRDD = session.sparkContext.makeRDD(List((1, "zhangsan", 21), (2, "lisi", 24)))
    val udaf=new MyAgeAvg
    //注册聚合函数
    session.udf.register("avgAGE",udaf)
    //使用
    val rdd = listRDD.map {
      case (id, name, age) => {
        User(id, name, age)
      }
    }
    val ds = rdd.toDS().createOrReplaceTempView("user")
    session.sql("select avgAGE(age) from user ").show()
  }

  /**
   * 样例类
   */
  case  class User(id:Int ,name:String,age:Int)

  /**
   * 自定义弱类型聚合函数
   * 1.继承UserDefinedAggregateFunction
   * 2.实现方法
   */
class  MyAgeAvg extends UserDefinedAggregateFunction{
    //函数输入数据结构
    override def inputSchema: StructType = {
      new StructType().add("age",LongType)
    }
    //计算时数据结构
    override def bufferSchema: StructType = {
      new StructType().add("sum",LongType).add("count",LongType)
    }
    //函数返回的数据类型
    override def dataType: DataType =DoubleType
    //函数是否稳定
    override def deterministic: Boolean = true
    //计算前缓冲区初始化
    override def initialize(buffer: MutableAggregationBuffer): Unit = {
      buffer(0)=0L
      buffer(1)=0L
    }
    //更新数据
    override def update(buffer: MutableAggregationBuffer, input: Row): Unit = {
      buffer(0)=buffer.getLong(0)+input.getLong(0)
      buffer(1)=buffer.getLong(1)+1
    }
    //将多个节点缓冲区合
    override def merge(buffer1: MutableAggregationBuffer, buffer2: Row): Unit = {
      buffer1(0)=buffer1.getLong(0)+buffer2.getLong(0)
      buffer1(1)=buffer1.getLong(1)+buffer2.getLong(1)

    }

    //计算
    override def evaluate(buffer: Row): Any ={
      buffer.getLong(0).toDouble/buffer.getLong(1)
    }
  }
}

强类型:规定数据类型

object Spark_SQL5 {
  def main(args: Array[String]): Unit = {
    val conf = new SparkConf().setMaster("local[*]").setAppName("word")
    val session = new SparkSession.Builder().config(conf).getOrCreate()
    import session.implicits._
    //创建RDD
    val listRDD = session.sparkContext.makeRDD(List((1, "zhangsan", 21), (2, "lisi", 24)))
    val udaf = new MyAgeAvgClass
    //将聚合函数转换为查询的列
    val avg = udaf.toColumn.name("avgAge")
    //使用
    val rdd = listRDD.map {
      case (id, name, age) => {
        User(id, name, age)
      }
    }
    val ds = rdd.toDS()
    ds.select(avg).show

  }

  /**
   * 样例类
   */
  case class User(id: Int, name: String, age: Int)

  /**
   *定义数据类型
   */
  case class AvgBuff(var sum:Int,var count:Int)
  /**
   * 自定义强类型聚合函数
   * 1.Aggregator,设定泛型
   * 2.实现方法
   */
  class MyAgeAvgClass extends Aggregator[User,AvgBuff,Double] {
    //缓冲区初始化
    override def zero: AvgBuff = {AvgBuff(0,0)}
    //聚合数据
    override def reduce(b: AvgBuff, a: User): AvgBuff = {
      b.sum=b.sum+a.age
      b.count=b.count+1
      b
    }
    //缓冲区的合并操作
    override def merge(b1: AvgBuff, b2: AvgBuff): AvgBuff = {
      b1.sum=b1.sum+b2.sum
      b1.count=b1.count+b2.count
      b1
    }
    //计算
    override def finish(reduction: AvgBuff): Double = {
      reduction.sum.toDouble/reduction.count
    }

    override def bufferEncoder: Encoder[AvgBuff] = Encoders.product

    override def outputEncoder: Encoder[Double] = Encoders.scalaDouble
  }
}

SparkSession:

SparkSession是为用户提供了统一的切入点,他是用来替代SparkContext的为了方便,SparkSession的出现是因为Spark的操作RDD时对于不同的API需要不同的Context使用使用SparkSession来将他们整合起来。

优点:

为用户提供一个统一的切入点使用Spark 各项功能

允许用户通过它调用 DataFrame 和 Dataset 相关 API 来编写程序

减少了用户需要了解的一些概念,可以很容易的与 Spark 进行交互

与 Spark 交互之时不需要显示的创建 SparkConf, SparkContext 以及 SQlContext,这些对象已经封闭在 SparkSession 中

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值