Spark SQL基础笔记及简单案例

Spark SQL是一个用来处理结构化数据的Spark组件,是Spark上一个分布式的SQL查询引擎,并拥有自己的SQL解析器。

Spark SQL 特点:

  • 快速
  • 具有统一的数据访问方式:兼容Hive,从各种结构化数据源中读取数据
  • 基于内存的列式存储技术
  • 面向多种语言
  • 具有良好的组件兼容性

Spark SQL的执行流程:

  • 步骤1.SQL解析(语法结构层面的解析)
  • 步骤2.绑定(语义层面的解析)
  • 步骤3. 逻辑计划优化(怎么做最好)
  • 步骤4. 物理计划生成与执行(SQL语句映射成Spark程序执行)

Spark SQL提供了一个叫做DataFrames的可编程抽象数据模型。DataFrame是以“命名列”方式(类似关系表的字段定义)组织起来的分布式数据集,与传统关系型数据库中的表结构类似。不同于RDD,DataFrames封装了数据的结构信息。

Spark SQL交互入口:

  • Spark 1.x:SQLContext
import.sqlContext.implicits._
val conf= new SparkConf().setAppName("SQL_Advanced_case").setMaster("local")
val sc=new SparkContext(conf)
val sqlContext=new SQLContext(sc)
  • Spark 2.2 : SparkSession (包含SparkContext和SQLContext对象)
val spark= SparkSession.builder().appName(“SparkSQLTest”).getOrCreate()

创建DataFrame:

  • 基于RDD建DataFrame
    • 方法1. 基于反射机制创建(使用case class创建样例类,eg:case class Student(id: String, name : String, age: Int)
    • 方法2. 自定义转换接口创建(在不知道列以及列的类型的情况基于已有的RDD构造)
  • 基于Parquet类型文件创建DataFrame(Spark SQL默认的数据源类型就是Parquet)
val students = sqlContext.parquetFile(“hdfs://node01:9000/sqldata/ students.parquet")
  • 基于JSON类型文件创建DataFrame

保存DataFrame:

  • 使用registerTempTable保存为临时表,应用程序退出后自动销毁
  • 使用saveAsTable方法将数据以表的形式持久化到存储系统上
  • 使用cacheTable将数据存储到内存中,性能调优重要方式,为了提高SQL查询效率,推荐使用(uncacheTable删除)

DataFrame常见操作:
Spark SQL基础笔记及简单案例_第1张图片


Spark SQL简单案例:

链接: https://pan.baidu.com/s/1mhO5vkO 密码: 5f9w

————————————案例1————————————

spark-shell下操作:

import org.apache.spark.sql.types._   
import org.apache.spark.sql._         
import org.apache.spark._
import sqlContext.implicits._

1.利用反射机制创建students.txt对应的DataFrame,其中包含id、name、age三个字段。

case class Student(id: String, name : String, age: Int)
val students_rdd=sc.textFile("hdfs://node01:9000/sqldata/students.txt").map(_.split(",")).map(p => Student(p(0), p(1), p(2).trim.toInt))
val students=students_rdd.toDF()

其中,p(2).trim.toInt 将学生表中的age字段数据整理转化为Int

2.查看所有学生的姓名

students.select(col("name")).show
students.select($"age").show

3.查询所有学生的年龄,并按照年龄降序排序。

students.select($"age").orderBy(col("age").desc).show
students.select($"age").orderBy($"age".desc).show

4.查询年龄小于19或年龄大于21的所有学生。

students.registerTempTable("tb_students")
sqlContext.sql("select name,age from tb_students where (age>21) or (age<19)").show

5.计算所有学生的平均年龄。

sqlContext.sql("select avg(age) as averageAge from tb_students").show
sqlContext.sql("select sum(age)/10 as averageAge from tb_students").show

6.将age字段重命名为stu_age。

students.withColumnRenamed("age","stu_age").show

7.添加scholarship字段,每个学生的scholarship项是其龄*20。

students.withColumn("scholarship",col("age")*20).show
students.withColumn("scholarship",$"age"*20).show

8.将添加scholarship字段后的DataFrame分别以Parquet和JSON格式保存至HDFS上。

val students_j=students.withColumn("scholarship",col("age")*20).write.save("hdfs://node01:9000/sqldata/students_j.json")
val students_p=students.withColumn("scholarship",col("age")*20).write.save("hdfs://node01:9000/sqldata/students_p.parquet")

9.利用自定义接口创建scores.txt对应的DataFrame,其中包含id、course_id、score三个字段。

val scores_rdd=sc.textFile("hdfs://node01:9000/sqldata/scores.txt")
val schemaString="id course_id score"
val schema=StructType(schemaString.split(" ").map(fieldname=> StructField(fieldname, StringType, true)))
val rowRDD=scores_rdd.map(_.split(",")).map(p=>Row(p(0), p(1), p(2).trim))
val scores=sqlContext.createDataFrame(rowRDD, schema) 
scores.registerTempTable("tb_scores")

10.按照课程编号分组,查看每门课的平均成绩,并按课程编号升序排序。

sqlContext.sql("select avg(score) as averageScore from tb_scores group by course_id").show

11.按照课程编号分组,查看个学生的姓名和其所有课程的平均成绩,并在统计结果中筛选出平均成绩大于72的同学。

sqlContext.sql("select id,avg(score) as averageScore from tb_scores group by id having averageScore>72 order by averageScore desc").show

————————————案例2————————————
首先构建数据库Students,然后分别创建上述表,在此基础上实现以下查询:
1.查询创建的五个表的概要信息。
2.查询各院系学生总数。
3.查询各院系学生奖学金的总和并排序。
4.查询各院系学生的平均学分并排序。
5.统计各学院每年学生参与创新项目所获得的创新学分数总数。

sqlContext.sql("CREATE DATABASE STUDENTS")
sqlContext.sql("USE STUDENTS")

创建学生信息表students

sqlContext.sql("CREATE TABLE IF NOT EXISTS students(id STRING, name STRING, gender STRING, age INT, year STRING, dep_id STRING) ROW FORMAT DELIMITED FIELDS TERMINATED BY ',' LINES TERMINATED BY '\n'")

加载数据

sqlContext.sql("LOAD DATA INPATH 'hdfs://node01:9000/sqldata/students2.txt' OVERWRITE INTO TABLE students")

查询概要

sqlContext.sql("select * from students").printSchema

同理,创建、加载、查询其余四个表
查询各院系学生总数

sqlContext.sql("select b.name, count(a.id) from students a join departments b on a.dep_id=b.dep_id group by b.name").show

查询各院系学生奖学金的总和并排序

sqlContext.sql("select b.name,sum(c.amount) as sum from students a join departments b on a.dep_id=b.dep_id join scholarship c on a.id = c.id group by b.name order by sum asc").show
sqlContext.sql("select b.name,sum(c.amount) as sum from students a join departments b on a.dep_id=b.dep_id join scholarship c on a.id = c.id group by b.name order by sum desc").show

查询各院系学生的平均学分并排序

sqlContext.sql("select b.name,avg(c.credit) as average_credit from students a join departments b on a.dep_id=b.dep_id join scores c on a.id = c.id group by b.name order by average_credit").show

统计各学院每年学生参与创新项目所获得的创新学分数总数

sqlContext.sql("select b.name, h.year,sum(h.pro_score) as sum from(select a.id,p.year,p.level*( p.theory+p.practice)/16 as pro_score,a.dep_id from projects p join students a on a.id=p.id) h join departments b on h.dep_id=b.dep_id group by b.name, h.year").show

你可能感兴趣的:(spark)