✎ 学习目标
在很多情况下,开发工程师并不了解Scala语言,也不了解Spark常用API,但又非常想要使用Spark框架提供的强大的数据分析能力。Spark的开发工程师们考虑到了这个问题,利用SQL语言的语法简洁、学习门槛低以及在编程语言普及程度和流行程度高等诸多优势,从而开发了Spark SQL模块,通过Spark SQL,开发人员能够通过使用SQL语句,实现对结构化数据的处理。
Spark SQL的简介
Spark SQL是Spark用来处理结构化数据的一个模块,它提供了一个编程抽象结构叫做DataFrame的数据模型(即带有Schema信息的RDD),Spark SQL作为分布式SQL查询引擎,让用户可以通过SQL、DataFrames API和Datasets API三种方式实现对结构化数据的处理。
Spark SQL主要提供了以下三个功能:
Spark SQL可从各种结构化数据源中读取数据,进行数据分析。
Spark SQL包含行业标准的JDBC和ODBC连接方式,因此它不局限于在Spark程序内使用SQL语句进行查询。
Spark SQL可以无缝地将SQL查询与Spark程序进行结合,它能够将结构化数据作为Spark中的分布式数据集(RDD)进行查询。
Spark SQL架构
Spark SQL架构与Hive架构相比,把底层的MapReduce执行引擎更改为Spark,还修改了Catalyst优化器,Spark SQL快速的计算效率得益于Catalyst优化器。从HiveQL被解析成语法抽象树起,执行计划生成和优化的工作全部交给Spark SQL的Catalyst优化器进行负责和管理。
Spark要想很好地支持SQL,需要完成解析(Parser)、优化(Optimizer)、执行(Execution)三大过程。
Catalyst优化器在执行计划生成和优化的工作时,离不开内部的五大组件。
Spark SQL工作流程:
1.下在解析SQL语句之前,会创建SparkSession,涉及到表名、字段名称和字段类型的元数据都将保存在SessionCatalog中;
2.当调用SparkSession的sql()方法时就会使用SparkSqlParser进行解析SQL语句,解析过程中使用的ANTLR进行词法解析和语法解析;
3.使用Analyzer分析器绑定逻辑计划,在该阶段,Analyzer会使用Analyzer Rules,并结合SessionCatalog,对未绑定的逻辑计划进行解析,生成已绑定的逻辑计划;
4.使用Optimizer优化器优化逻辑计划,该优化器同样定义了一套规则(Rules),利用这些规则对逻辑计划和语句进行迭代处理;
5.使用SparkPlanner对优化后的逻辑计划进行转换,生成可以执行的物理计划SparkPlan;
6.使用QueryExecution执行物理计划,此时则调用SparkPlan的execute()方法,返回RDDs。
DataFrame简介
DataFrame可以看作是分布式的Row对象的集合,在二维表数据集的每一列都带有名称和类型,这就是Schema元信息,这使得Spark框架可获取更多数据结构信息,从而对在DataFrame背后的数据源以及作用于DataFrame之上数据变换进行针对性的优化,最终达到提升计算效率。
DataFrame的创建
创建DataFrame的两种基本方式:
1 zhangsan 20
2 lisi 29
3 wangwu 25
4 zhaoliu 30
5 tianqi 35
6 jerry 40
2.通过文件直接创建DataFrame
我们通过Spark读取数据源的方式进行创建DataFrame
scala > val personDF = spark.read.text("/spark/person.txt")
personDF: org.apache.spark.sql.DataFrame = [value: String]
scala > personDF.printSchema()
root
|-- value: String (Nullable = true)
3.RDD直接转换为DataFrame
scala > val lineRDD = sc.textFile("/spark/person.txt").map(_.split(" "))
lineRDD: org.apache.spark.rdd.RDD[Array[String]] = MapPartitionsRDD[6] at map at <console>:24
scala > case class Person(id:Int,name:String,age:Int) defined class Person
scala > val personRDD = lineRDD.map(x => Person(x(0).toInt, x(1), x(2).toInt))
personRDD: org.apache.spark.rdd.RDD[Person] = MapPartitionsRDD[7] at map at <console>:27
scala > val personDF = personRDD.toDF()
personDF: org.apache.spark.sql.DataFrame = [id: int, name: string ... 1 more field]
DataFrame的常用操作
DataFrame提供了两种语法风格,即DSL风格语法和SQL风格语法。二者在功能上并无区别,仅仅是根据用户习惯,自定义选择操作方式。
DSL风格:DataFrame提供了一个领域特定语言(DSL)以方便操作结构化数据。
SQL风格:在程序中直接使用spark.sql()方式执行SQL查询,结果将作为一个DataFrame返回,使用SQL风格操作的前提是将DataFrame注册成一个临时表。
1. DSL风格操作DataFrame
DSL风格操作DataFrame的常用方法,具体如下表如示。
2. SQL风格操作DataFrame
scala > personDF.registerTempTable("t_person")
scala > spark.sql("select * from t_person order by age desc limit 2").show()
+---+------+---+
| id| name|age|
+---+------+---+
| 6| jerry| 40|
| 5|tianqi| 35|
+---+------+---+
3. 查询年龄大于25的人的信息
scala > spark.sql("select * from t_person where age > 25").show()
+---+-------+---+
| id | name |age|
+---+-------+---+
| 2 | lisi | 29 |
| 4 | zhaoliu| 30 |
| 5 | tianqi | 35 |
| 6 | jerry | 40 |
+---+-------+---+
Dataset简介:
Dataset是从Spark1.6 Alpha版本中引入的一个新的数据抽象结构,最终在Spark2.0版本被定义成Spark新特性。Dataset提供了特定域对象中的强类型集合,也就是在RDD的每行数据中添加了类型约束条件,只有约束条件的数据类型才能正常运行。Dataset结合了RDD和DataFrame的优点,并且可以调用封装的方法以并行方式进行转换等操作。
RDD、DataFrame及Dataset的区别
RDD数据的表现形式,即序号(1),此时RDD数据没有数据类型和元数据信息。
DataFrame数据的表现形式,即序号(2),此时DataFrame数据中添加Schema元数据信息(列名和数据类型,如ID:String),DataFrame每行类型固定为Row类型,每列的值无法直接访问,只有通过解析才能获取各个字段的值。
Dataset数据的表现形式,序号(3)和(4),其中序号(3)是在RDD每行数据的基础之上,添加一个数据类型(value:String)作为Schema元数据信息。而序号(4)每行数据添加People强数据类型,在Dataset[Person]中里存放了3个字段和属性,Dataset每行数据类型可自定义,一旦定义后,就具有错误检查机制。
Dataset对象的创建
1、通过SparkSession中的createDataset来创建Dataset
scala > val personDs=spark.createDataset(sc.textFile("/spark/person.txt"))
personDs: org.apache.spark.sql.Dataset[String] = [value: string]
scala > personDs.show()
+---------------+
| value |
+---------------+
|1 zhangsan 20|
|2 lisi 29|
|3 wangwu 25|
|4 zhaoliu 30 |
|5 tianqi 35|
|6 jerry 40|
+---------------+
2、DataFrame通过“as[ElementType]”方法转换得到Dataset
scala> spark.read.text("/spark/person.txt").as[String]
res14: org.apache.spark.sql.Dataset[String] = [value: string]
scala> spark.read.text("/spark/person.txt").as[String].toDF()
res15: org.apache.spark.sql.DataFrame = [value: string]
Spark官方提供了两种方法实现从RDD转换得到DataFrame。
第一种方法是利用反射机制来推断包含特定类型对象的Schema,这种方式适用于对已知数据结构的RDD转换
第二种方法通过编程接口构造一个Schema,并将其应用在已知的RDD数据中。
反射机制推断Schema
Windows系统开发Scala代码,可使用本地环境测试(需要先准备本地数据文件)。我们可以很容易的分析出当前数据文件中字段的信息,但计算机无法直观感受字段的实际含义,因此需要通过反射机制来推断包含特定类型对象的Schema信息,实现将RDD转换成DataFrame。
1.创建Maven工程。打开IDEA开发工具,创建名为“spark_chapter04”的Maven工程。
2.添加依赖。在pom.xml文件中添加Spark SQL依赖。
3.定义case class样例类、字段和属性,样例类的参数名会被利用反射机制作为列名。通过sc对象读取文件生成一个RDD,将RDD 与样例类匹配,调用toDF()方法将RDD转换为DataFrame。
编程方式定义Schema
当Case类不能提前定义Schema时,就需要采用编程方式定义Schema信息,实现RDD转换DataFrame的功能。
1.创建一个Row对象结构的RDD。
2.基于StructType类型创建Schema。
3.通过SparkSession提供的createDataFrame()方法来拼接Schema,来实现RDD转换成DataFrame。
val mysqlDF : DataFrame =
spark.read.jdbc ("jdbc:mysql://192.168.121.134:3306/spark","person",properties)
personDF.write.mode("append").jdbc( "jdbc:mysql://192.168.121.134:3306/spark","spark.person",prop)
操作Hive数据集
操作步骤:
1.准备环境,使Spark可以访问Hive,Spark SQL连接Hive。
2.在Hive中创建数据库和表。
3.Spark SQL操作Hive数据库。
4.向Hive表写入数据。
加个关注吧 持续更新!
加个关注吧 持续更新!
加个关注吧 持续更新!
Thank you !Thank you !Thank you !