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)
}
}