SparkSQL 创建DataFrame
在 Spark SQL 中 SparkSession 是创建 DataFrame 和执行 SQL 的入口,创建DataFrame 有三种方式:
- 通过 Spark 的数据源进行创建;
- 从一个存在的 RDD 进行转换;
- 还可以从 HiveTable 进行查询返回。
测试数据:
波波波结衣 18 13698786412
安倍晋三 66 18036963212
工藤新一 21 18696478962
野原新之助 5 16987159638
1 通过 Spark 的数据源进行创建
package org.example
import org.apache.log4j.{Level, Logger}
import org.apache.spark.{SparkConf, SparkContext}
import org.apache.spark.sql.{Row, SQLContext, SparkSession}
object DateFrame {
def main(args: Array[String]): Unit = {
//屏蔽日志
Logger.getLogger("org.apache.spark").setLevel(Level.WARN)
Logger.getLogger("org.eclipse.jetty.server").setLevel(Level.OFF)
//设置 SparkSession
var spark:SparkSession = SparkSession.builder()
.appName("cai")
.master("local[*]")
.getOrCreate() //新建一个 sparkSession
//第一种方式:读取 json 文件
//注意:如果从内存中获取数据, spark 可以知道数据类型具体是什么。
//如果是数字,默认作为 Int 处理;
//但是从文件中读取的数字,不能确定是什么类型,所以用 bigint 接收,
//可以和Long 类型转换,但是和 Int 不能进行转换
var df = spark.read.json("test/users.json")
var df1 = spark.read.format("json").load("test/users.json")
//第二种方式:通过 读取 csv 文件
var df2 = spark.read.option("header", false).option("encoding", "gbk").csv("test/users.csv")
var df3 = spark.read.format("csv").option("header", false).option("encoding", "gbk").load("test/users.csv")
//通过 SEQ
var seq = Seq(("工藤新一",25),("小兰",25),("波波老师",65))
var df4 = spark.createDataFrame(seq).toDF("name","age")
//或者 var df4 = seq.toDF("name","age")
//通过 json格式的RDD --弃用了
var conf = new SparkConf().setMaster("local[*]").setAppName("cai")
var sc = new SparkContext(conf)
var rdd = sc.parallelize(Array(
"{\"name\":\"ming\",\"age\":20,\"phone\":15552211521}",
"{\"name\":\"hong\", \"age\":19,\"phone\":13287994007}",
"{\"name\":\"zhi\", \"age\":21,\"phone\":15552211523}"
))
var df5 = spark.read.json(rdd)
df5.show()
//读取数据库
见下文
//动态创建schema
见下文
}
}
2 从一个存在的 RDD 进行转换
在 IDEA 中开发程序时, 如果需要 RDD 与 DF 或者 DS 之间互相操作,那么需要引入
import spark.implicits._
这里的 spark 不是 Scala 中的包名,而是创建的 sparkSession 对象的变量名称,所以必须先创建 SparkSession 对象再导入。这里的 spark 对象不能使用 var 声明,因为 Scala 只支持val 修饰的对象的引入。
2.1 手动转换
这种方法不能自定义 Schame 的类型
package org.example
import org.apache.log4j.{Level, Logger}
import org.apache.spark.sql.SparkSession
import org.apache.spark.{SparkConf, SparkContext}
/**
* 本案列是通过 手动转换 方式来将 RDD 转换为 DataFrame
* 与样例类的区别是不能指定类型
*/
object RDDToFrame {
def main(args: Array[String]): Unit = {
//去除日志
Logger.getLogger("org.apache.spark").setLevel(Level.WARN)
Logger.getLogger("org.eclipse.jetty.server").setLevel(Level.OFF)
var conf = new SparkConf().setAppName("cai").setMaster("local[*]")
var sc = new SparkContext(conf)
//注意這個地方必須要用 val
val spark = SparkSession.builder().config(conf).getOrCreate()
//涉及到 RDD , DataFrame , DataSet 之间的操作时
//需要导⼊ 隐式转换 : import spark.implicits._
import spark.implicits._
//创建一个RDD
var rdd = sc.textFile("test/users.txt")
//注意以下的三种写法,仅当是关于语法的参考
//第一种
var re = rdd.map(x => {
// 先对每一行进行切分,然后对切割的部分进行
var cai = x.split(" ");
(cai(0),cai(1).toInt,cai(2))
})
//第二种
var re1 = rdd.map(x=>{
( x.split(" ")(0),x.split(" ")(1).toInt,x.split(" ")(2) )
})
//第三种
var re2 = rdd.map(x=>x.split(" ")).map(x=>(x(0),x(1).toInt,x(2)))
// re.toDF("neme1","age1","phone1").show()
// re1.toDF("name2","age2","phone2").show()
// re2.toDF("name3","age3","phone3").show()
val df1 = re.toDF("neme1","age1","phone1").createTempView("table1")
val df2 = re.toDF("name2","age2","phone2").createTempView("table2")
val df3 = re.toDF("name3","age3","phone3").createTempView("table3")
var result1 = spark.sql("select * from table1")
var result2 = spark.sql("select * from table2")
var result3 = spark.sql("select * from table3")
result1.show()
result2.show()
result3.show()
}
}
2.2 通过样例类反射转换(最常⽤)
这种方法可以自定义 Schame 的类型
package org.example
import org.apache.log4j.{Level, Logger}
import org.apache.spark.{SparkConf, SparkContext}
import org.apache.spark.sql.{SQLContext, SparkSession}
import org.apache.spark.sql.types.{IntegerType, StringType, StructField, StructType}
object RddToDateFrame {
def main(args: Array[String]): Unit = {
//屏蔽日志
Logger.getLogger("org.apache.spark").setLevel(Level.WARN)
Logger.getLogger("org.eclipse.jetty.server").setLevel(Level.OFF)
var conf = new SparkConf().setAppName("caicia").setMaster("local[*]")
var sc = new SparkContext(conf)
//此处必须要使用 val
val spark:SparkSession = SparkSession.builder()
.config(conf)
.getOrCreate()
//涉及到 RDD , DataFrame , DataSet 之间的操作时
//需要导⼊ 隐式转换 : import spark.implicits._
import spark.implicits._
//创建一个RDD
var rdd = sc.textFile("test/users.txt")
//注意以下的三种写法,仅当是关于语法的参考
// 对每一行的数据切割的同时进行处理
var re = rdd.map(x=> User(
x.split(" ")(0), x.split(" ")(1).toInt, x.split(" ")(2)
))
//或者这么写也行
// 先将每一行的数据切割完,然后在进行处理
var re1 = rdd.map(lines => {
var cai = lines.split(" ");
User(cai(0),cai(1).toInt,cai(2))
})
//或者这么写呗
var re2 = rdd.map(x=>x.split(" ")).map(x=>User(x(0),x(1).toInt,x(2)))
// 创建全局的临时表
re.toDF.createGlobalTempView("users1")
re1.toDF().createGlobalTempView("users2")
re2.toDF().createGlobalTempView("users3")
//除了用 to.DF 以外,还可以用 createDataFrame
//spark.createDataFrame(re).createTempView("test")
//spark.sql("select * from test").show()
// 用 sql 进行查询
var result1 = spark.sql("select * from global_temp.users1")
var result2 = spark.sql("select * from global_temp.users2")
var result3 = spark.sql("select * from global_temp.users3")
// 查看类型为 Dataset
println(result1.getClass.getSimpleName)
result1.show()
result2.show()
result3.show()
}
//样例类 可以自定义类型
case class User(name:String, age:Int ,phone:String)
}
2.3 通过 API 的⽅式
通过StructType方式创建DataFrame
这种方法可以自定义 Schame 的类型
理解:我认为这种方式与上一种的 case class 方式没有本质上的区别,只不过 case class 是自己定义的,而 StructType 是已经定义好的我们拿过来用的。
package org.example
import org.apache.log4j.{Level, Logger}
import org.apache.spark.sql.types.{DataTypes, StructField, StructType}
import org.apache.spark.sql.{Row, SparkSession}
import org.apache.spark.{SparkConf, SparkContext}
object RDDSchemaToFrame {
def main(args: Array[String]): Unit = {
//去除日志
Logger.getLogger("org.apache.spark").setLevel(Level.WARN)
Logger.getLogger("org.eclipse.jetty.server").setLevel(Level.OFF)
var conf = new SparkConf().setAppName("cai").setMaster("local[*]")
var sc = new SparkContext(conf)
//注意這個地方必須要用 val
val spark = SparkSession.builder().config(conf).getOrCreate()
//涉及到 RDD , DataFrame , DataSet 之间的操作时
//需要导⼊ 隐式转换 : import spark.implicits._
import spark.implicits._
//创建一个RDD
var rdd = sc.textFile("test/users.txt")
var rowrdd = rdd.map(lines => {
var re = lines.split(" ");
Row(re(0),re(1).toInt,re(2))
})
// StructType 本身就是一个 case class ,跟用样例类来处理本质上没什么区别
//关联schema(字段名称、字段类型、是否可以为空)
val schametypes:StructType = StructType(Array
( StructField("name",DataTypes.StringType),
StructField("age",DataTypes.IntegerType),
StructField("phone",DataTypes.StringType)
)
)
//将RowRDD与StructType中的schema关联
var re = spark.createDataFrame(rowrdd,schametypes)
//查看 re 的类型为 Dataset
println(re.getClass.getSimpleName)
//生成全局临时表
re.createGlobalTempView("sparktable")
var df = spark.sql("select * from global_temp.sparktable")
df.show()
}
}
3 从 HiveTable 进行查询返回
学习的机器上暂时没装 hive ,暂时不想写,心情不好,过段时间再说。