文章目录
SparkSQL 核心编程
新的起点
Spark Core中,如果想要执行应用程序,需要首先构建上下文环境对象SparkContext,Spark SQL其实可以理解为对Spark Core的一种封装,不仅仅在模型上进行了封装,上下文环境对象也进行了封装。
在老的版本中,SparkSQL提供两种SQL查询起始点:一个叫SQLContext,用于Spark自己提供的SQL查询;一个叫HiveContext,用于连接Hive的查询。
SparkSession是Spark最新的SQL查询起始点,实质上是SQLContext和HiveContext的组合,所以在SQLContex和HiveContext上可用的API在SparkSession上同样是可以使用的。SparkSession内部封装了SparkContext,所以计算实际上是由sparkContext完成的。当我们使用
spark-shell 的时候, spark 会自动的创建一个叫做spark的SparkSession, 就像我们以前可以自动获取到一个sc来表示SparkContext
DataFrame
Spark SQL的DataFrame API 允许我们使用 DataFrame 而不用必须去注册临时表或者生成 SQL 表达式。DataFrame API 既有 transformation操作也有action操作。
创建DataFrame
从Spark数据源进行创建
- 查看Spark支持创建文件的数据源格式
scala> spark.read.
csv format jdbc json load option options orc parquet schema table text textFile
- 读取json文件创建DataFrame
scala> val df = spark.read.json("examples/src/main/resources/people.json")
df: org.apache.spark.sql.DataFrame = [age: bigint, name: string]
注意:如果从内存中获取数据,spark可以知道数据类型具体是什么。
如果是数字,默认作为Int处理;但是从文件中读取的数字,不能确定是什么类型,所以用bigint接收,可以和Long类型转换,但是和Int不能进行转换。
- 展示结果
scala> df.show
+----+-------+
| age| name|
+----+-------+
|null|Michael|
| 30| Andy|
| 19| Justin|
+----+-------+
从RDD进行转换
从Hive Table进行查询返回
SQL语法
这种风格的查询必须要有临时视图或者全局视图来辅助
- 读取JSON文件创建DataFrame
scala> val df = spark.read.json("examples/src/main/resources/people.json")
df: org.apache.spark.sql.DataFrame = [age: bigint, name: string]
- 对DataFrame创建一个临时表
scala> df.createOrReplaceTempView("people")
- 通过SQL语句实现查询全表
scala> val sqlDF = spark.sql("select * from people")
sqlDF: org.apache.spark.sql.DataFrame = [age: bigint, name: string]
- 结果展示
scala> sqlDF.show
+----+-------+
| age| name|
+----+-------+
|null|Michael|
| 30| Andy|
| 19| Justin|
+----+-------+
注意:普通临时表是Session范围内的,如果想应用范围内有效,可以使用全局临时表。
使用全局临时表时需要全路径访问,如global_temp.people
- 对于DataFrame创建一个全局表
scala> df.createGlobalTempView("people")
- 通过SQL语句实现查询全表
scala> spark.sql("select * from global_temp.people").show
+----+-------+
| age| name|
+----+-------+
|null|Michael|
| 30| Andy|
| 19| Justin|
+----+-------+
scala> spark.newSession.sql("select * from global_temp.people").show
+----+-------+
| age| name|
+----+-------+
|null|Michael|
| 30| Andy|
| 19| Justin|
+----+-------+
DSL语法
DataFrame提供一个特定领域语言(domain-specific language, DSL)去管理结构化数据。
可以在Scala,Java,Python和R中使用DSL,使用DSL语法风格不必去创建临时视图了。
- 创建一个DataFrame
scala> val df = spark.read.json("examples/src/main/resources/people.json")
df: org.apache.spark.sql.DataFrame = [age: bigint, name: string]
- 查看DataFrame的Schema信息
scala> df.printSchema
root
|-- age: long (nullable = true)
|-- name: string (nullable = true)
- 只查看"name"列数据
scala> df.select("name").show
+-------+
| name|
+-------+
|Michael|
| Andy|
| Justin|
+-------+
- 查看"username"列数据以及"age+1"数据
注意:涉及到计算的时候,每列都必须使用$,或者采用引号表达式:单引号+字段名
scala> df.select($"name", $"age" + 1).show
+-------+---------+
| name|(age + 1)|
+-------+---------+
|Michael| null|
| Andy| 31|
| Justin| 20|
+-------+---------+
scala> df.select('name, 'age + 1).show
+-------+---------+
| name|(age + 1)|
+-------+---------+
|Michael| null|
| Andy| 31|
| Justin| 20|
+-------+---------+
scala> df.select('name, 'age + 1 as "newAge").show
+-------+------+
| name|newAge|
+-------+------+
|Michael| null|
| Andy| 31|
| Justin| 20|
+-------+------+
- 查看"age"大于"30"的数据
scala> df.filter('age >= 30).show
+---+----+
|age|name|
+---+----+
| 30|Andy|
+---+----+
scala> df.filter($"age" >= 30).show
+---+----+
|age|name|
+---+----+
| 30|Andy|
+---+----+
- 按照"age"分组,查看数据条数
scala> df.groupBy("age").count.show
+----+-----+
| age|count|
+----+-----+
| 19| 1|
|null| 1|
| 30| 1|
+----+-----+
RDD转换为DataFrame
在IDEA中开发程序时,如果需要RDD与DF或者DS之间相互操作,那么需要引入import spark.implicits._
这里的spark不是Scala中的包名,而是创建的SparkSession对象的变量名称,所以必须先创建SparkSession对象再导入。
这里的spark对象不能使用var声明,因为Scala只支持val修饰的对象的引入
spark-shell中无需导入,自动完成此操作。
scala> val peopleRDD = sc.textFile("examples/src/main/resources/people.txt")
peopleRDD: org.apache.spark.rdd.RDD[String] = examples/src/main/resources/people.txt MapPartitionsRDD[150] at textFile at <console>:24
scala> peopleRDD.toDF("line").show
+-----------+
| line|
+-----------+
|Michael, 29|
| Andy, 30|
| Justin, 19|
+-----------+
实际开发中,一般通过样例类将RDD转换为DataFrame
scala> case class User(name: String, age: Int)
defined class User
scala> sc.makeRDD(List(("dsy", 18), ("sarah", 19))).map(t => User(t._1, t._2)).toDF.show
+-----+---+
| name|age|
+-----+---+
| dsy| 18|
|sarah| 19|
+-----+---+