使用IDEA工具练习SparkSql

前言

Spark SQL是Spark用来处理结构化数据的一个模块,它提供了2个编程抽象:DataFrame和DataSet,并且作为分布式SQL查询引擎的作用。

Spark SQL的特点:

1)易整合;
2)统一的数据访问方式;
3)兼容Hive;
4)标准的数据连接。

DataFrame的介绍:

DataFrame也是一个分布式数据容器。然而DataFrame更像传统数据库的二维表格,除了数据以外,还记录数据的结构信息,即schema;
Spark SQL记录数据的结构信息,即schema;
同时,与Hive类似,DataFrame也支持嵌套数据类型(struct、array和map)。

DataSet的介绍:

DataFrame只是知道字段(类型),但是不知道字段的类型;
但是DataSet不仅仅知道字段,而且知道字段类型,
样例类被用来在Dataset中定义数据的结构信息,样例类中每个属性的名称直接映射到DataSet中的字段名称;

RDD、DataFrame、DataSet三者之间的转化:

		RDD -> Dataset 
			val ds = rdd.toDS()
		RDD -> DataFrame 
			val df = spark.read.json(rdd)
		Dataset -> RDD
			val rdd = ds.rdd
		Dataset -> DataFrame
			val df = ds.toDF()
		DataFrame -> RDD
			val rdd = df.toJSON.rdd
		DataFrame -> Dataset
			val ds=df.as[类型]

案例:

项目目录:

使用IDEA工具练习SparkSql_第1张图片

利用IDEA工具编写WordCount:

 //使用开发工具完成 Spark 的wordcount的开发
    //local模式
    //创建SparkConf对象
    //设置Spark计算框架 的运行环境   local[*]本地
    val config: SparkConf = new SparkConf().setMaster("local[*]").setAppName("wordCount")
    //创建Spark上下文对象
     val sc = new  SparkContext(config)
    //读取文件,将文件内容一行一行读取出来
    val lines: RDD[String] = sc.textFile("input/")    //input下的两个文件
    //将一行一行数据分解一个一个的单词
    val words: RDD[String] = lines.flatMap(_.split(" "))
    //为了统计方便  将单词的数据结果进行结构的转换
   val wordToOne: RDD[(String, Int)] = words.map((_, 1))
    //对转换结构后的数据进行聚合
    val wordToSum: RDD[(String, Int)] = wordToOne.reduceByKey(_+_)
    //将统计结果采集出来
    val result: Array[(String, Int)] = wordToSum.collect()
    //将结果打印
    //println(result)
    result.foreach(println)

程序运行结果:

20/02/22 23:38:20 INFO DAGScheduler: Job 0 finished: collect at SparkWordCount.scala:25, took 0.382258 s
(scala,1)
(word,1)
(hello,2)
20/02/22 23:38:20 INFO SparkContext: Invoking stop() from shutdown hook

用IDEA工具使用SparkSql:

  def main(args: Array[String]): Unit = {
    //创建配置对象
  val sparkConf = new SparkConf().setMaster("local[*]").setAppName("SparkSql_02Demo")
  //创建SparkSql得环境对象
  // val session : SparkSession= new SparkSession(sparkConf)    错误原因 SparkSession构造函数
  val spark: SparkSession =  SparkSession.builder().config(sparkConf).getOrCreate()
  //读取数据DataFrame
  val frame:DataFrame= spark.read.text("input/1.txt")

  //将DataFtame转换为一张表
  frame.createOrReplaceTempView("Test")
  //采用sql得语法访问数据
  spark.sql("select * from Test").show()

  //展示数据
  // frame.show()
  //释放资源
  spark.stop

程序运行结果:

+-----------+
|      value|
+-----------+
| hello word|
|hello scala|
+-----------+

使用IDEA工具进行SparkSql类型之间的转换:

object SparkSql_03TransForm {    //类型之间转换
  def main(args: Array[String]): Unit = {
    //创建配置对象
    val sparkConf = new SparkConf().setMaster("local[*]").setAppName("SparkSql_02Demo")
    //创建SparkSql得环境对象
    // val session : SparkSession= new SparkSession(sparkConf)    错误原因 SparkSession构造函数
    val spark: SparkSession =  SparkSession.builder().config(sparkConf).getOrCreate()
    //SparkSession  包含了   sparkContext

    //进行转换之前  需要引入隐士转换规则
    //这里得spark不是包得名字  是SparkSession对象得名字
    import spark.implicits._

    //创建RDD
      val rdd: RDD[(Int, String,Int)] = spark.sparkContext.makeRDD(List( (1, "liuyan", 20), (2, "wen", 24), (3, "huanhuan",20)))

   /* //从这一步直接转换DS   RDD--> DS      另一种方案 已验证
    val UsreRDD: RDD[Usre] = rdd.map {
      case (id, name, age) => {
        Usre(id, name, age)
      }
    }
    val UsreDS: Dataset[Usre] = UsreRDD.toDS()
    val UsreRdd1: RDD[Usre] = UsreDS.rdd
    UsreRdd1.foreach(println)*/

    //转换为DF  RDD--> DataFrame        当前数据没有结构  设置结构
      val df: DataFrame = rdd.toDF("id","name","age")
    //转换为DS    DataFrame--> Dataset               没有结构 需要增加一个样例类
    val ds: Dataset[Usre] = df.as[Usre]
    //转换为DF    Dataset-->DataFrame
    val df1: DataFrame = ds.toDF()
    //转换为RDD   DataFrame-->RDD
    val rdd1: RDD[Row] = df1.rdd
  //最后类型是Row  特别注意
    rdd1.foreach(Row =>{
      //获取数据时 可以通过索引访问数据
     println(Row.getString(1))
    })
    //展示数据
    // frame.show()
    //释放资源
    spark.stop
  }
}

case class Usre(id:Int,name:String,age:Int)

程序运行结果显示:

20/02/22 23:44:32 INFO CodeGenerator: Code generated in 11.3352 ms
huanhuan
wen
liuyan
20/02/22 23:44:32 INFO Executor: Finished task 1.0 in stage 0.0 (TID 1). 1318 bytes result sent to driver

使用IDEA工具之用户自定义聚合函数练习:

object SparkSql_04UDAF {   //用户自定义得聚合函数
  def main(args: Array[String]): Unit = {

    //创建配置对象
    val sparkConf = new SparkConf().setMaster("local[*]").setAppName("SparkSql_02Demo")
    //创建SparkSql得环境对象
    // val session : SparkSession= new SparkSession(sparkConf)    错误原因 SparkSession构造函数
    val spark: SparkSession =  SparkSession.builder().config(sparkConf).getOrCreate()
    //SparkSession  包含了   sparkContext

    //进行转换之前  需要引入隐士转换规则
    //这里得spark不是包得名字  是SparkSession对象得名字
    import spark.implicits._

    //用户自定义得聚合函数
    //创建聚合函数对象  构造
    val udaf=new MyAgeAvgFunction
    //注册聚合函数
    spark.udf.register("avgAge",udaf)
    //使用聚合函数
    val frame: DataFrame = spark.read.json("input/user.json")

    frame.createOrReplaceTempView("user")

    spark.sql("select avgAge(age) from user").show()
    //释放资源
    spark.stop()

  }
}

    //声明自定义聚合函数
    //1 . 继承UserDefinedAggregateFunction
    //2. 实现方法
    class MyAgeAvgFunction extends UserDefinedAggregateFunction {
     //函数得输入数据结构   inputSchema:在里面增加结构 类型
      override def inputSchema: StructType = {
        new StructType().add("age",LongType)   //指定一个   类型是long
      }

      //缓冲  计算时数据结构  buffer:缓冲区   增加两个结构  sum count
      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
      }
      //将多个节点得缓冲区合并    merge合并
      override def merge(buffer1: MutableAggregationBuffer, buffer2: Row): Unit = {
        //sum
        buffer1(0)=buffer1.getLong(0)+ buffer2.getLong(0)
        //count
        buffer1(1)=buffer1.getLong(1)+buffer2.getLong(1)
      }
      // 计算  把最终结果计算
      override def evaluate(buffer: Row): Any = {
        buffer.getLong(0).toDouble / buffer.getLong(1)
      }
    }

程序运行结果:

计算年龄的平均值:
		{"name":"Andy", "age":30}
		{"name":"Justin", "age":30}
+---------------------+
|myageavgfunction(age)|
+---------------------+
|                 30.0|
+---------------------+

使用idea工具练习强类型聚合函数:

使用起来更方便
object SparkSql_05UDAFClass {//强类型聚合函数
  def main(args: Array[String]): Unit = {
    //创建配置对象
    val sparkConf = new SparkConf().setMaster("local[*]").setAppName("SparkSql_02Demo")
    //创建SparkSql得环境对象
    // val session : SparkSession= new SparkSession(sparkConf)    错误原因 SparkSession构造函数
    val spark: SparkSession =  SparkSession.builder().config(sparkConf).getOrCreate()
    //SparkSession  包含了   sparkContext

    //进行转换之前  需要引入隐士转换规则
    //这里得spark不是包得名字  是SparkSession对象得名字
    import spark.implicits._

    //创建聚合函数
    val udaf=new MyAgeAvgClassFunction

    //将我们聚合函数转换为查询列
    val avgAge: TypedColumn[UserBean, Double] = udaf.toColumn.name("avgAge")

    val frame: DataFrame = spark.read.json("input/user.json")
    //Dataset对类型做了约束
   val userDS: Dataset[UserBean] = frame.as[UserBean]

    //应用函数
    userDS.select(avgAge).show()

    //释放资源
    spark.stop
  }
}

case class UserBean(name : String,age:BigInt)
case class AvgBuffer(var sum:BigInt,var count:Int)

//声明 用户自定义聚合函数 (强类型)
//1 . 继承 Aggregator   设定泛型
//2. 实现方法
class MyAgeAvgClassFunction extends Aggregator[UserBean,AvgBuffer,Double] {
 //初始化
  override def zero: AvgBuffer = {
    AvgBuffer(0,0)
  }
//聚合数据  更新操作
  override def reduce(b: AvgBuffer, a: UserBean): AvgBuffer = {
    b.sum=b.sum + a.age
    b.count=b.count+1
    b
  }
  //缓冲区合并操作
  override def merge(b1: AvgBuffer, b2: AvgBuffer): AvgBuffer = {
    b1.sum=b1.sum+b2.sum
    b1.count=b1.count+b2.count
    b1
  }
//完成计算
  override def finish(reduction: AvgBuffer): Double ={
    reduction.sum.toDouble /  reduction.count
  }
  //自定义类型就用这个
  override def bufferEncoder: Encoder[AvgBuffer] =  Encoders.product
  //Double 就用这个
  override def outputEncoder: Encoder[Double] = Encoders.scalaDouble
}

程序运行结果:

+------+
|avgAge|
+------+
|  30.0|
+------+

完!

你可能感兴趣的:(使用IDEA工具练习SparkSql)