目录
对于spark,无论core还是streaming,亦或sql,structed streaming
最好的资料就是官网示例+源码
本人的spark sql的学习路线是
1.官网示例(入门,了解)
2.Dataset/Dataframe的各个方法(了解之后才能在面对需求是知道哪个最合适)
3.关键的源码
本篇为第一步,官网示例,Dataset简称为ds,Dataframe简称为df
1.Dataset/Dataframe基本操作
def main(args: Array[String]): Unit = {
val spark=SparkSession
.builder()
.appName("demo1")
.master("local[*]")
.getOrCreate()
//用于隐式转换,将RDD转为DataFrame
import spark.implicits._
//读取json创建DataFrame,以下为json内容
//{"name":"Michael"}
//{"name":"Andy", "age":30}
//{"name":"Justin", "age":19}
val df=spark.read.json("C:\\zlq\\data\\people.json")
df.show()//将json字段作为字段名
+----+-------+
| age| name|
+----+-------+
|null|Michael|
| 30| Andy|
| 19| Justin|
+----+-------+
df.printSchema()//以树的形式打印schema,类型为推断出来的
root
|-- age: long (nullable = true)
|-- name: string (nullable = true)
df.select($"name").show()//查询某列
+-------+
| name|
+-------+
|Michael|
| Andy|
| Justin|
+-------+
df.select($"name",$"age"+1).show()//将age加1
+-------+---------+
| name|(age + 1)|
+-------+---------+
|Michael| null|
| Andy| 31|
| Justin| 20|
+-------+---------+
df.filter($"age">20).show()//查询年龄20以上的
+---+----+
|age|name|
+---+----+
| 30|Andy|
+---+----+
df.groupBy($"age").count().show()//计算各个年龄的人数,null值会参与计算
+----+-----+
| age|count|
+----+-----+
| 19| 1|
|null| 1|
| 30| 1|
+----+-----+
//以上是df的操作,接下来我们用sql的方式与df交互
//创建全局临时视图,就是表名,默认库位global_temp
df.createGlobalTempView("people")
spark.sql("select * from global_temp.people").show()//查看所有
+----+-------+
| age| name|
+----+-------+
|null|Michael|
| 30| Andy|
| 19| Justin|
+----+-------+
//创建ds,跟rdd类似,有两种途径,一种df转,一种集合转
val ds1=Seq(1,2,3).toDS()
ds.show()
+-----+
| 2|
| 3|
| 4|
+-----+
val peopleDS=spark.read.json("C:\\zlq\\data\\people.json").as[Person]//as将df转ds
peopleDS.show()
+----+-------+
| age| name|
+----+-------+
|null|Michael|
| 30| Andy|
| 19| Justin|
+----+-------+
}
case class Person(name:String,age:Int)
2.RDD转Dataset/Dataframe
def main(args: Array[String]): Unit = {
val spark=SparkSession
.builder()
.appName("demo2")
.master("local[*]")
.getOrCreate()
import spark.implicits._
//1.使用反射将RDD[Class]转为df
val df=spark.sparkContext
.textFile("C:\\zlq\\data\\people.txt")
.map(_.split(","))
.map(ele=>(Person(ele(0),ele(1).trim.toInt))).toDF()//toDF()转为DF
df.createOrReplaceTempView("people")//创建临时视图
val teendf=spark.sql("select name,age from people where age between 13 and 19")
teendf.map(ele=>"name:"+ele(0)).show()//可以通过下标处理sql返回结果
teendf.map(ele=>"name:"+ele.getAs[String]("name")).show()//也可以通过字段名处理
//2.编程方式指定schema
val schemaString="name age"//df字段名
val fields=schemaString.split(" ")
.map(ele=>StructField(ele,StringType,nullable = true))//返回Array[StructFiield]
val schema=StructType(fields)
val peopleRDD=spark.sparkContext.textFile("C:\\zlq\\data\\people.txt")
val rowRDD=peopleRDD
.map(_.split(","))
.map(ele=>Row(ele(0),ele(1).trim)
//将schema作用到rdd上
val df=spark.createDataFrame(rowRDD,schema)
}
case class Person(name:String,age:Int)
3.不同数据集
官网说parquet挺多的,但我们用的是orc,所以就不在这多写了。
def main(args: Array[String]): Unit = {
val spark=SparkSession
.builder()
.appName("demo_2")
.master("local[*]")
.getOrCreate()
import spark.implicits._
//读取json数据
val peopleDF=spark.read.json("C:\\zlq\\data\\people.json")
peopleDF.printSchema()
peopleDF.createGlobalTempView("people")
spark.sql("select * from global_temp.people where age between 13 and 19").show()
}
最后是用的最多的,hive数据源,之前写过篇配置spark sql查询hive的,有兴趣的可以看看
def main(args: Array[String]): Unit = {
val warehouseLocation = new File("spark-warehouse").getAbsolutePath
val spark=SparkSession
.builder()
.appName("demo_3")
.master("local[*]")
.config("spark.sql.warehouse.dir",warehouseLocation)
.enableHiveSupport()//设置支持hive
.getOrCreate()
import spark.implicits._
import spark.sql
sql("show databases").show()//查看hive的数据库
val apidf=spark.sql(
"""
|select to_date(date) t,count(1)
|from data.api
|where to_date(date)>'2019-02-13'
|group by to_date(date)
|order by t
""".stripMargin).show()
}
说下spark.sql.warehouse.dir这个参数,刚开始resources下是有hive的hive-site.xml的
本人是在idea中测试的,如果配置了
val warehouseLocation = new File("spark-warehouse").getAbsolutePath
xxx
.config("spark.sql.warehouse.dir",warehouseLocation)
会在项目下创建一个spark_warehouse的目录,由于有hive-site.xml,所以该目录为空
把hive-site.xml删掉后,执行以下代码
sql("show databases").show()
sql("create database data")
sql("show databases").show()
执行结果为:
在看项目目录
spark-warehouse下多了data库,并且多了个元数据的目录
所以就算未配置hive-site.xml,spark也会提供hive的功能,两个目录分别存储元数据和数据。
如果,有了hive-site.xml,不配置spark.sql.warehouse.dir也没关系。