1.SparkSql简介
- Spark SQL是Spark处理数据的一个模块
- 专门用来处理结构化数据的模块,像json,parquet,avro,csv,普通表格数据等均可。
- 与基础RDD的API不同,SparkSQL中提供的接口将提供给更多关于结构化数据和计算的信息,并针对这些信息,进行额外的处理优化。
2.SparkSql操作方式
- SparkSql shell 类似于hive shell
- DataFrames API
与RDD相似,增加了数据结构描述信息部分 - DataSets API
集成了RDD强类型和DataFrames结构化的优点
3.DataFrames相关操作
综合示例-1.6.x
import org.apache.spark.SparkConf
import org.apache.spark.SparkContext
import org.apache.spark.sql.SQLContext
object SparkSqlTest {
def main(args: Array[String]) {
val conf = new SparkConf()
conf.setMaster("local");
conf.setAppName("TestSparkSql");
val sc = new SparkContext(conf)
val sqlContext = new SQLContext(sc)
// 添加将RDD转化为DataFrame的功能包引入
import sqlContext.implicits._
val df = sqlContext.read.json("file:\\E:\\test\\job003\\sparksql\\input_weibo.json")
//默认显示内容的top20
df.show()
// 打印内容对应的表结构
df.printSchema()
// 选择内容当中的某一个列对应的内容
df.select("content").show()
// 选择任意列并进行自定义操作
df.select(df("content"), df("commentCount"), df("commentCount") + 10000).show()
// 选择评论数大于100的数据显示出来
df.filter(df("commentCount") > 100).show()
// 按userId进行分组计数统计
df.groupBy("userId").count().show()
//分组统计结果按默认升序排列
df.groupBy("userId").count().orderBy("count").show()
//分组统计结果按降序排列
import org.apache.spark.sql.functions._
df.groupBy("userId").count().orderBy(desc("count")).show()
sc.stop();
}
}
综合示例-2.3.x
import org.apache.spark.SparkConf
import org.apache.spark.SparkContext
import org.apache.spark.sql.SQLContext
import org.apache.spark.sql.SparkSession
object TestSparkSqlFor2_3_x {
def main(args: Array[String]): Unit = {
//1、构建spark session
val sparkSession = SparkSession
.builder()
.appName("SparkSql-2.3.2-TestCase")
.master("local[*]")
.getOrCreate()
// For implicit conversions like converting RDDs to DataFrames
import sparkSession.implicits._
//2、构建data frames
val df = sparkSession.read.json("F:\\test_sbt\\FirstSpark4Scala\\input_json.txt")
//3、df算子操作
// 打印内容对应的表结构
df.printSchema()
// 选择内容当中的某一个列对应的内容
df.select("content").show()
// 选择任意列并进行自定义操作
df.select(df("content"), df("commentCount"), df("commentCount") + 10000).show()
// 选择评论数大于100的数据显示出来
df.filter(df("commentCount") > 100).show()
// 按userId进行分组计数统计
df.groupBy("userId").count().show()
//分组统计结果按默认升序排列
df.groupBy("userId").count().orderBy("count").show()
//分组统计结果按降序排列
import org.apache.spark.sql.functions._
df.groupBy("userId").count().orderBy(desc("count")).show()
//4、停掉相关会话
sparkSession.stop()
}
}
4.RDD转化为DataFrame
将无结构化数据转化成有结构化数据(两种方式)
- 反射推断
- 程序编码实现数据与结构的对应,达到转化目标
2.3代码实现
import org.apache.spark.SparkConf
import org.apache.spark.SparkContext
import org.apache.spark.sql.SQLContext
import org.apache.spark.sql.SparkSession
import org.apache.spark.sql.types.StructType
import org.apache.spark.sql.types.StructField
import org.apache.spark.sql.types.StringType
import org.apache.spark.sql.Row
object TestRddToDataFrameFor2_3_x {
def main(args: Array[String]): Unit = {
//1、构建spark session
val sparkSession = SparkSession
.builder()
.appName("SparkSql-2.3.2-TestCase")
.master("local[*]")
.getOrCreate()
// For implicit conversions like converting RDDs to DataFrames
import sparkSession.implicits._
//2、构建scheme
val schema =
StructType(
"stdNo name classNo className".split(" ").map(fieldName => StructField(fieldName, StringType, true)))
//3、构建rdd,linesRDD
val studentRDD = sparkSession.sparkContext.textFile("F:\\test_sbt\\FirstSpark4Scala\\student_mysql.txt")
//4、将linesRDD转换成Row rdd
val rowRDD = studentRDD.map(_.split("\\t")).map(p => Row(p(0), p(1), p(2), p(3)))
//5、创建df,由row rdd + scheme
val studentDataFrame = sparkSession.createDataFrame(rowRDD, schema)
//6、df算子操作
studentDataFrame.printSchema()
studentDataFrame.show()
//7、停掉相关会话
sparkSession.stop()
}
}
5.DataFrame数据持久化
• 综合示例实现-2.3.x(与1.6.x差距核心在sparkSession抽象)
import org.apache.spark.SparkConf
import org.apache.spark.SparkContext
import org.apache.spark.sql.SQLContext
import org.apache.spark.sql.SparkSession
import org.apache.spark.sql.types.StructType
import org.apache.spark.sql.types.StructField
import org.apache.spark.sql.types.StringType
import org.apache.spark.sql.Row
object TestSparksqlPersistFor2_3_x {
def main(args: Array[String]): Unit = {
//1、构建spark session
val sparksql = SparkSession
.builder()
.appName("SparkSql-2.3.2-TestCase")
.master("local[*]")
.getOrCreate()
// For implicit conversions like converting RDDs to DataFrames
import sparksql.implicits._
//2、构建scheme
val df = sparksql.read.json("F:\\test_sbt\\FirstSpark4Scala\\input_json.txt")
//3、注册成表
df.createTempView("weibo")
//4、df算子操作
var resultDF = sparksql.sql("select * from weibo")
resultDF.repartition(1).write.format("parquet").save("F:\\test_sbt\\FirstSpark4Scala\\save3")
//5、停掉相关会话
sparksql.stop()
}
}
6.DataSets的Spark2.3.2版本上的应用
package com.tl.job019.sparksql
import org.apache.spark.sql.SparkSession
//样例类
case class Student(name: String, age: Long, address: String)
/**
* 抽象数据类型DataSet测试类
*/
object TestSparkSqlDataSet {
def main(args: Array[String]): Unit = {
//1、构建spark session
val sparkSession = SparkSession
.builder()
.appName("SparkSql-2.3.2-TestCase")
.master("local[*]")
.getOrCreate()
//引入自动隐式类型转换
import sparkSession.implicits._
// 从基础数据对象类型创建DataSet
val primitiveDS = Seq(1, 2, 3).toDS()
val col = primitiveDS.map(_ + 1).collect() // Returns: Array(2, 3, 4)
col.foreach(println)
println("-----------------")
primitiveDS.show()
// 已为样例类case class创建完成编码类Encoder
val caseClassDS = Seq(Student("脱口秀大会", 3, "北京")).toDS()
caseClassDS.show()
// 指定相应的文件导入形成样例类对应的DataSet,通过json的key和样例类的字段名称对应即可
val path = "F:\\test_sbt\\FirstSpark4Scala\\student_data.txt"
val peopleDS = sparkSession.read.json(path).as[Student]
peopleDS.select("name", "age", "address").show()
//关停会话上下文
sparkSession.stop()
}
}
7.多数据集抽象类型对比分析
spark抽象数据集列表
- RDD
- DataFrame
- DataSet
相同点:
- 全都是spark平台下的分布式弹性数据集,为处理超大型数据提供便利
- 三者都有惰性机制,在进行Transform操作时不会立即执行,在遇到Action操作时会正式提交作业执行。
- 均采用spark的内存运算和优化策略,内存使用和执行效率上均可以得到保障。
- 均有partition的概念,便于分布式并行计算处理,达到分而治之。 均有许多共同的函数,如map、filter、sort等。
- 在进行三者的相关操作时候,个别特殊操作时必须引入一个相同的包依赖。( 早期称为 import sqlContext.implicits.,最新版本称为import spark.implicits.)
- DF和DS均可以通过模式匹配获取内部的变量类型和值。
- DF和DS产生于SparkSql,天然支持SparkSql。
• 区别点
RDD
- 不支持SparkSql操作,均需进行转成DF或是DS才行。
- 类型是安全的,编译时候即可检查出类型错误。(强类型)
- 机器间通信、IO操作均需要序列化、反序列化对象,性能开销大。
DataFrame
- 有scheme的RDD:比RDD增加了数据的描述信息。
- 比RDD的API更丰富,增加了针对结构化数据API。
- 只有一个固定类型的DataSet,即为DataFrame=DataSet[Row]
- 序列化和反序列化时做了结构化优化,减少了不必要的结构化信息的序列化,提高了执行效率
DataSet
- 强类型的DataFrame,与DF有完全相同的成员函数。
- 每行的类型不固定,需要使用模式匹配case class后,获取实际的类信息、字段类型、字段值。
- 访问对象数据时,比DF更加直接简单。
- 在序列化和反序列化时,引入了Encoder机制,达到按需序列化和反序列化,不必像之前整个对象操作了,进一步提高了效率。