文章目录
- 说明
- 分享
- 资料
- 优势
- 运行方式
- 优化器及执行计划
- 整体流程
- 自定义优化器
- 自定义执行计划
- 代码实例
- 指定Schema格式
- case class方式
- 结果数据保存到数据库
- 总结
说明
本博客每周五更新
Spark Sql模块用于处理结构化数据,结构化数据指DataFrame数据。
Spark sql是从shark发展而来,shark则是为了兼容Hive数据库,实现sql任务。
分享
- 大数据博客列表
资料
- Spark Sql官网地址
优势
- 简化数据操作,Spark Sql支持在DataFrame基础上实现sql语句操作,降低了数据操作的技术门槛,可以让产品经理或数据分析工作者,直接高效从数据中提取价值信息。
- 灵活性强,支持自定义UDF
- 支持多种类型数据加载和存储,文件格式如:json、parquet、jdbc、orc、libsvm、csv、text,提供jdbc数据源,并且支持自定义数据源。
运行方式
Spark Sql支持用户提交SQL文件,提供三种方式编写SQL:
- Spark 代码
- Spark-Sql shell方式,类似spark-submite可设置部署模式和资源,可使用Spark-sql –help 查看配置参数说明
- thriftserver方式, thriftserver jdbc/odbc的实现类似于hive1.2.1的hiveserver2,可以使用spark的beeline命令来测试jdbc server。
优化器及执行计划
整体流程
总体执行流程如上,从提供的输入API(SQL,Dataset, dataframe)开始,依次经过unresolved逻辑计划,解析的逻辑计划,优化的逻辑计划,物理计划,然后根据cost based优化,选取一条物理计划进行执行。
流程简化可分为4步
- analysis:Spark 2.0 以后语法树生成使用的是antlr4,之前是scalaparse。
- logical optimization:常量合并,谓词下推,列裁剪,boolean表达式简化,和其它的规则
- physical planning:物理规划
- Codegen:codegen技术是用scala的字符串插值特性生成源码,然后使用Janino,编译成java字节码。
自定义优化器
- 实现,继承Rule[LogicalPlan]
- 注册:
spark.experimental.extraOptimizations= Seq(MultiplyOptimizationRule)
- 使用:
selectExpr("amountPaid* 1")
自定义执行计划
主要是实现重载count函数的功能
- 物理计划:继承SparkLan实现doExecute方法
- 逻辑计划:继承SparkStrategy实现apply
- 注册到Spark执行策略:
spark.experimental.extraStrategies =Seq(countStrategy)
- 使用:
spark.sql("select count(*) fromtest")
代码实例
scala语言三种Spark Sql操作实例
指定Schema格式
import org.apache.spark.sql.{Row, SQLContext, SaveMode, SparkSession}
import org.apache.spark.sql.types._
import org.apache.spark.{SparkConf, SparkContext}
object SpecifyingSchema {
def main(args: Array[String]) {
//创建Spark Session对象
val spark = SparkSession.builder().master("local").appName("UnderstandingSparkSession").getOrCreate()
//从指定的地址创建RDD
val personRDD = spark.sparkContext.textFile("D:\\temp\\student.txt").map(_.split(" "))
//通过StructType直接指定每个字段的schema
val schema = StructType(
List(
StructField("id", IntegerType, true),
StructField("name", StringType, true),
StructField("age", IntegerType, true)
)
)
//将RDD映射到rowRDD
val rowRDD = personRDD.map(p => Row(p(0).toInt, p(1).trim, p(2).toInt))
//将schema信息应用到rowRDD上
val personDataFrame = spark.createDataFrame(rowRDD, schema)
//注册表
personDataFrame.createOrReplaceTempView("t_person")
//执行SQL
val df = spark.sql("select * from t_person order by age desc limit 4")
//显示结果
df.show()
//停止Spark Context
spark.stop()
}
}
case class方式
import org.apache.spark.sql.SparkSession
//使用case class
object Demo2 {
def main(args: Array[String]): Unit = {
//创建SparkSession
val spark = SparkSession.builder().master("local").appName("My Demo 1").getOrCreate()
//从指定的文件中读取数据,生成对应的RDD
val lineRDD = spark.sparkContext.textFile("d:\\temp\\student.txt").map(_.split(" "))
//将RDD和case class 关联
val studentRDD = lineRDD.map( x => Student(x(0).toInt,x(1),x(2).toInt))
//生成 DataFrame,通过RDD 生成DF,导入隐式转换
import spark.sqlContext.implicits._
val studentDF = studentRDD.toDF
//注册表 视图
studentDF.createOrReplaceTempView("student")
//执行SQL
spark.sql("select * from student").show()
spark.stop()
}
}
//case class 一定放在外面
case class Student(stuID:Int,stuName:String,stuAge:Int)
结果数据保存到数据库
import java.util.Properties
import org.apache.spark.sql.{Row, SparkSession}
import org.apache.spark.sql.types.{IntegerType, StringType, StructField, StructType}
//作用:读取本地一个文件, 生成对应 DataFrame,注册表
object Demo1 {
def main(args: Array[String]): Unit = {
//创建SparkSession
val spark = SparkSession.builder().master("local").appName("My Demo 1").getOrCreate()
//从指定的文件中读取数据,生成对应的RDD
val personRDD = spark.sparkContext.textFile("d:\\temp\\student.txt").map(_.split(" "))
//创建schema ,通过StructType
val schema = StructType(
List(
StructField("personID",IntegerType,true),
StructField("personName",StringType,true),
StructField("personAge",IntegerType,true)
)
)
//将RDD映射到Row RDD 行的数据上
val rowRDD = personRDD.map(p => Row(p(0).toInt,p(1).trim,p(2).toInt))
//生成DataFrame
val personDF = spark.createDataFrame(rowRDD,schema)
//将DF注册成表
personDF.createOrReplaceTempView("myperson")
//执行SQL
val result = spark.sql("select * from myperson")
//显示
//result.show()
//将结果保存到oracle中
val props = new Properties()
props.setProperty("user","scott")
props.setProperty("password","tiger")
result.write.jdbc("jdbc:oracle:thin:@192.168.88.101:1521/orcl.example.com","scott.myperson",props)
//如果表已经存在,append的方式数据
//result.write.mode("append").jdbc("jdbc:oracle:thin:@192.168.88.101:1521/orcl.example.com","scott.myperson",props)
//停止spark context
spark.stop()
}
}
总结
Spark Sql是spark实现易用性的重要构成部分,加强了非专业开发者业务处理能力,也增强了功能开发的灵活性。
马上元旦,20年许愿每周更新一篇博客,年初坚持到现在只剩一周,给自己鼓掌,加油。