Spark SQL中创建 DataFrame 方法

在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

步骤:

  1. 要在工程中添加spark-hive的依赖jar
  2. 要在工程中添加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> 
  1. 要在工程中添加hive-site.xml/core-site.xml/hdfs-site-xml配置文件
  2. 创建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()
  1. 加载hive中的表
spark.sql(
  """
    |select * from stu
    |
    |""".stripMargin).show()
发布了5 篇原创文章 · 获赞 5 · 访问量 153

猜你喜欢

转载自blog.csdn.net/weixin_45687351/article/details/103811097
今日推荐