在Spark SQL中SparkSession是创建DataFrames和执行SQL的入口
创建DataFrames有三种方式:
(1) 从一个已存在的RDD进行转换
(2) 从JSON/Parquet/CSV/ORC/JDBC等结构化数据源直接创建
(3) 从Hive Table进行查询返回
核心:
创建DataFrame,需要创建 “RDD + 元信息schema定义”
rdd来自于数据
schema则可以由开发人员定义,或者由框架从数据中推断
1. 从RDD创建DataFrame
1.1 从RDD[Case class类]创建DataFrame
定义一个case class来封装数据,如下,Stu是一个case class类
case class Stu(id: Int, name: String, age: Int, city: String, score: Double)
代码如下:
//RDD[String]
val rdd: RDD[String] = saprk.sparkContext.textFile("doc/stu.csv")
val data: RDD[Stu] = rdd.map(line => {
//切分字段
val arr = line.split(",")
//每一行数据对应一个caseclass对象
Stu(arr(0).toInt, arr(1), arr(2).toInt, arr(3), arr(4).toDouble)
})
// .toDF
import saprk.implicits._
val df: DataFrame = data.toDF()
1.2 从RDD[Tuple]创建DataFrame
val rddTuple: RDD[(Int, String, Int, String, Double)] = rdd
// 切分字段
.map(_.split(","))
// 将每一行数据变形成一个多元组tuple
.map(arr => (arr(0).toInt, arr(1), arr(2).toInt, arr(3), arr(4).toDouble))
import spark.implicits._
//指定字段名称
val df2 = rddTuple.toDF("id","name","age","city","score")
1.3 从RDD[JavaBean]创建DataFrame
注:此处所说的Bean,指的是用java定义的bean
public class Stu2 {
private int id;
private String name;
private int age;
private String city;
private double score;
public Stu2(int id, String name, int age, String city, double score) {
this.id = id;
this.name = name;
this.age = age;
this.city = city;
this.score = score;
}
public int getId() {
return id;
}
public void setId(int id) {
示例代码:
val rddBean: RDD[Stu2] = rdd
// 切分字段
.map(_.split(","))
// 将每一行数据变形成一个JavaBean
.map(arr => new Stu2(arr(0).toInt,arr(1),arr(2).toInt,arr(3),arr(4).toDouble))
val df = spark.createDataFrame(rddBean,classOf[Stu2])
df.show()
注:RDD[JavaBean]在spark.implicits._中没有toDF的支持
1.4 从RDD[普通Scala类]中创建DataFrame
普通scala bean类定义:
class Stu3(
@BeanProperty
val id: Int,
@BeanProperty
val name: String,
@BeanProperty
val age: Int,
@BeanProperty
val city: String,
@BeanProperty
val score: Double)
示例代码:
val rddStu3: RDD[Stu3] = rdd
// 切分字段
.map(_.split(","))
// 将每一行数据变形成一个普通Scala对象
.map(arr => new Stu3(arr(0).toInt, arr(1), arr(2).toInt, arr(3), arr(4).toDouble))
val df = spark.createDataFrame(rddStu3, classOf[Stu3])
df.show()
1.5 从RDD[Row]中创建DataFrame
注:DataFrame中的数据,本质上还是封装在RDD中,而RDD[ T ]总有一个T类型,DataFrame内部的RDD中的元素类型T即为框架所定义的Row类型;
val rddRow = rdd
// 切分字段
.map(_.split(","))
// 将每一行数据变形成一个Row对象
.map(arr => Row(arr(0).toInt, arr(1), arr(2).toInt, arr(3), arr(4).toDouble))
val schema = new StructType()
.add("id", DataTypes.IntegerType)
.add("name", DataTypes.StringType)
.add("age", DataTypes.IntegerType)
.add("city", DataTypes.StringType)
.add("score", DataTypes.DoubleType)
val df = spark.createDataFrame(rddRow,schema)
df.show()
2. 从结构化文件创建DataFrame
2.1 从JSON文件进行创建
val df = spark.read/*.schema(schema)*/.json("data/people.json")
df.printSchema()
df.show()
2.2 从csv文件进行创建DataFrame
2.2.1(不带header)进行创建
val df = spark.read.csv("data/stu.csv")
df.printSchema()
df.show()
2.2.2 从csv文件(不带header)自定义Schema进行创建
// 创建DataFrame时,传入自定义的schema
// schema在api中用StructType这个类来描述,字段用StructField来描述
val schema = new StructType()
.add("id", DataTypes.IntegerType)
.add("name", DataTypes.StringType)
.add("age", DataTypes.IntegerType)
.add("city", DataTypes.StringType)
.add("score", DataTypes.DoubleType)
val df = spark.read.schema(schema).csv("data/stu.csv")
df.printSchema()
df.show()
2.2.3 从csv文件(带header)进行创建
关键点——设置一个header=true的参数
val df = spark.read.option("header",true).csv("data/stu.csv")
df.printSchema()
df.show()
虽然字段名正确指定,但是字段类型还是无法确定,默认情况下全视作String对待,可以开启一个参数 inferSchema=true 来让框架对csv中的数据字段进行合理的类型推断
val df = spark.read
.option("header",true)
.option("inferSchema",true)
.csv("data/stu.csv")
df.printSchema()
df.show()
让框架自动推断schema,效率低不建议!
备注:
1、 如果只有option(“header”,true),则所有字段有名称但类型都为String
2、 如果有.option(“header”,true)和.option(“inferSchema”,true) ,则所有字段有名称和类型,效率低
3、 如果有option(“header”,true)和自定义schema则效率高
2.3 从Parquet文件进行创建
val df = spark.read.parquet("data/parquet")
3. 从外部服务器读取数据创建DataFrame
3.1 从JDBC连接数据库服务器进行创建
注:要使用jdbc连接读取数据库的数据,需要引入jdbc的驱动jar包依赖
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.39</version>
</dependency>
代码示例:
val props = new Properties()
props.setProperty("user","root")
props.setProperty("password","root")
val df = spark.read.jdbc("jdbc:mysql://localhost:3306/bigdata","student",props)
df.show()
3.2 从Hive仓库中加载创建DataFrame
步骤:
- 要在工程中添加spark-hive的依赖jar
- 要在工程中添加mysql连接驱动依赖jar
<dependency>
<groupId>org.apache.spark</groupId>
<artifactId>spark-hive_2.11</artifactId>
<version>2.4.4</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.48</version>
</dependency>
- 要在工程中添加hive-site.xml/core-site.xml/hdfs-site-xml配置文件
- 创建sparksession时需要调用.enableHiveSupport( )方法
val spark = SparkSession
.builder()
.appName(this.getClass.getSimpleName)
.master("local[*]")
// 启用hive支持,需要调用enableHiveSupport,还需要添加一个依赖 spark-hive
// 默认sparksql内置了自己的hive
// 如果程序能从classpath中加载到hive-site配置文件,那么它访问的hive元数据库就不是本地内置的了,而是配置中所指定的元数据库了
// 如果程序能从classpath中加载到core-site配置文件,那么它访问的文件系统也不再是本地文件系统了,而是配置中所指定的hdfs文件系统了
.enableHiveSupport()
.getOrCreate()
- 加载hive中的表
spark.sql(
"""
|select * from stu
|
|""".stripMargin).show()