spark-sql_WordCount_DSL

spark-sql_DSL

sparksql的单词统计

package com.sql
import org.apache.spark.sql.{DataFrame, SaveMode, SparkSession}

object Demo1WordCount {
  def main(args: Array[String]): Unit = {
    /**
     *
     * spark sql 的入口SparkSession
     * SparkSession也是spark新版本的新入口
     *
     */
    val spark: SparkSession = SparkSession
      .builder
      .master("local")
      .appName("sql")
      .getOrCreate()

    /**
     * 1.读取数据构建DataFrame,DF相当一一张表
     *
     */
    val lineDF: DataFrame = spark
      .read
      .format("csv")                 //指定数据的读取格式
      .schema("line STRING")   //指定字段和字段的分割类型
      .option("sep", "\t")                   //指定分割符,csv格式默认是逗号分割
      .load("data/word.txt")

    //打印表的结构
    lineDF.printSchema()

    //查看数据
    lineDF.show()

    /**
     * 2. 讲DF注册成一个视图才能写sql
     *
     */
    lineDF.createOrReplaceTempView("lines")

    /**
     * 3. 写sparkSql 统计单词的数量
     * spark Sql 语法完全兼容 hive sql
     *
     */

    val resultDF: DataFrame = spark.sql(
      """
        |select word,count(word)
        |from
        |(
        |select explode(split(line,",")) as word from lines
        |) as a
        |group by a.word
        |
        |""".stripMargin)

    /**
     * 4. 将数据保存到hdfs中
     *
     */
    resultDF
      .write
      .format("csv")    // 保存数据格式
      .option("sep","\t")        //数据分隔符
      .mode(SaveMode.Overwrite)  // 覆盖写数据
      .save("data/wc")
  }
}

spark 的类sql语言DSL

package com.sql

import org.apache.spark.sql.{DataFrame, SaveMode, SparkSession}

object Demo2DSLWC {
  def main(args: Array[String]): Unit = {

    /**
     * spark sql 的入口SparkSession
     *
     * sparkSession也是spark新版本通过的唯一入口
     */

    val spark: SparkSession = SparkSession
      .builder
      .master("local")
      .appName("sql")
      .getOrCreate()

    /**
     * DSL:类sql api ,介于代码和sql之间的一种写法
     *
     */

    val lineDF: DataFrame = spark
      .read
      .format("csv") //指定读取的数据格式
      .schema("line STRING") //指定字段名和字段类型
      .option("sep", "\t") //指定分隔符,csv默认的格式为逗号分割
      .load("data/word.txt")

    //输出数据的格式
    //lineDF.printSchema()

    //输出数据
    //lineDF.show()

    /**
     * DSL: 类sql api : 介于代码和sql之间的一种写法
     */

    //导入spark SQL的所有函数
    import org.apache.spark.sql.functions._
    //导入spark SQL的隐式转换
    import spark.implicits._
    //通过 $"line" 获取对象
    val resultDF: DataFrame = lineDF
      //将一行中的多个单词,拆分成多行
      .select(explode(split($"line", ",")) as "word")
      //按照单词分组
      .groupBy("word")
      //统计单词数量
      .agg(count($"word") as "c")

    //    resultDF.printSchema()
    //    resultDF.show()

    /**
     * 将数据保存在HDFS中
     *
     */
    resultDF
      .write
      .format("csv")
      .option("sep", "\t")
      .mode(SaveMode.Overwrite)
      .save("data/wc1")
  }
}

spark DSL 的API

package com.sql
import org.apache.spark.sql.expressions.Window
import org.apache.spark.sql.{DataFrame, SparkSession}

object Demo3DSLApi {
  def main(args: Array[String]): Unit = {
    /**
     * 创建spark SQL环境
     *
     */
    val spark: SparkSession = SparkSession
      .builder
      .master("local")
      .appName("sql")
      //指定spark SQL在shuffle之后的分区数,类似hive中设计reduce的数量
      .config("spark.sql.shuffle.partitions", 1)
      .getOrCreate()

    //读取一个json格式文件
    val stuDF: DataFrame = spark
      .read
      .format("json") // 指定读取数据的格式威json格式
      .load("data/students.json")

    /**
     * show : 查看df中的数据,相当于rdd中的action算子,会触发任务的执行
     *
     */
    //查看数据的格式
    //stuDF.printSchema()
    //打印数据
    //stuDF.show()
    //指定打印多少行
    //stuDF.show(39)
    //查看完整的数据
    //stuDF.show(false)

    /**
     * select : 选择数据,和sql中的select 用法基本一致
     * dls中的select 不能使用聚合函数,需要ogg中使用聚合函数
     * select 相当于rdd中的算子
     */

    //使用列明选择数据
    stuDF.select("id","age","name")//.show()
    //使用sql 表达式
    stuDF.selectExpr("name","age + 1 as age" )//.show()
    //使用隐式转换才能使用列对象,导入spark SQL函数,才能在DSL中使用汉函数
    import org.apache.spark.sql.functions._
    import spark.implicits._

    //使用隐式转换,才能使用列对象
    stuDF.select($"id",$"age" + 1000 as "age")//.show()

    //在select中使用sql的函数
    stuDF.select($"id",substring($"clazz",0,2) as "cc")//.show()

    /**
     *     where转换条件
     */

    stuDF.where(substring($"clazz",1,2) === "文科" ).show()

    //字符串sql表达式
    stuDF.where("gender = '女' and age = 23")//.show()
    //使用列对象
    stuDF.where($"gender" =!= "男" and $"age" === 22)// .show()
    //使用函数
    stuDF.where(substring($"clazz", 0, 2) === "文科")// .show()

    /**
     * groupBy ogg: 分组聚合,分组和聚合要一起使用
     * 分组聚合之后返回的DF只包含分组字段和聚合字段的
     * 能使用的聚合函数和sql中是一样的
     */
    stuDF
      .groupBy($"clazz")
      .agg(count("clazz") as "num_stu",round(avg($"age"),3) as "age_age")
      //.show()

    /**
     * order by :排序
     *
     */
    stuDF
      .groupBy($"clazz")
      .agg(count($"clazz") as "num_stu")
      .orderBy($"num_stu".desc)
      //.show()

    /**
     * join : 表关联
     *
     */
    val scoreDF: DataFrame = spark
      .read
      .format("csv")
      .option("sep", ",")
      .schema("id STRING,cid STRING,sco DOUBLE") // 指定列名
      .load("data/score.txt")

    //关联字段名不一样的方发
    //val joinDF: DataFrame = stuDF.join(scoreDF, $"id" === $"sid")

    //第二种方法,前提是字段名字一样
    val joinDF: DataFrame = stuDF.join(scoreDF, "id")
    joinDF.show()

    /**
     * 开窗函数
     * 统计每个班的总分前十名的学生
     *
     * withColumn: 在DF的基础上增加新的列
     *
     */

    joinDF
      .groupBy($"id",$"clazz") //按照学号和班级分组
      .agg(sum($"sco") as "sumSco") //计算总分
      //.select($"id", $"clazz", $"sumSco", row_number() over (Window.partitionBy($"clazz").orderBy($"sumSco".desc)) as "s")
      //简写,在前面的基础上增加列
      .withColumn("r",row_number() over Window.partitionBy($"clazz").orderBy($"sumSco".desc))
      .where($"r" <=10)
      .show(50)

    //我们用传统的sql方法写比较繁琐

    //这是用sql写就必须先创建视图
    joinDF.createOrReplaceTempView("student_score")

    spark.sql(
      """
        |select
        |*
        |from
        |(
        |select
        |id ,clazz,sumSco,row_number() over(partition by clazz order by sumSco desc) as r
        |from(
        |select id,clazz,sum(sco) as sumSco from student_score group by id,clazz
        |) as t
        |) as t2
        |where r<=10
        |""".stripMargin)//.show(50)
  }
}

posted @ 2022-07-17 22:21  a-tao必须奥利给  阅读(91)  评论(0)    收藏  举报