RDD转DataFrame常用的两种方式

        随着Spark1.4.x的更新,Spark提供更高阶的对象DataFrame,提供了比RDD更丰富的API操作,同时也支持RDD转DataFrame(下面简称“DF”),但是要注意,不是任意类型对象组成的RDD都可以转换成DF,,只有当组成RDD[T]的每一个T对象内部具有鲜明的字段结构时,才能隐式或者显示地创建DF所需要的Schema(结构信息),从而进行RDD->DF转换。下面介绍两种常用的RDD转DF的方式(示例Spark版本为2.2.0)。

准备文件:person3.txt

20,Michael,173,150
30,Andy,168,140
19,Justin,145,145
18,Sam,175,122
17,Jean,173,134
22,Jerry,180,99
26,Fasttson,150,145
23,Mivak,177,118
16,Heaat,168,129
36,Franc,165,138

一、使用反射机制推理出schema

        使用这种方式,往往是因为RDD[T]的T对象就已经是具有典型的一维表结构的字段结构对象,因此SparkSql可以自动推断出schema。常用的操作是使用样例对象(case class)。

package com.cjs
 
import org.apache.log4j.{Level, Logger}
import org.apache.spark.SparkConf
import org.apache.spark.sql.SparkSession
 
object RDDToDF1 {
    case class Person(name:String, age:Int)
 
    def main(args: Array[String]): Unit = {
        Logger.getLogger("org.apache.spark").setLevel(Level.ERROR)
 
        val conf = new SparkConf()
            .set("spark.sql.warehouse.dir","file:///e:/tmp/spark-warehouse")
            .set("spark.some.config.option","some-value")
 
        val ss = SparkSession
            .builder()
            .config(conf)
            .appName("RDDToDF")
            .master("local[2]")
            .getOrCreate()
 
        val path = "E:\\IntelliJ Idea\\sparkSql_practice\\src\\main\\scala\\com\\cjs\\person3.txt"
 
        import ss.implicits._
        val sc = ss.sparkContext
 
        val RDDPerson1 = sc.textFile(path)
        val RDDPerson = RDDPerson1.map(_.split(",")).map(p => Person(p(1),p(0).trim.toInt)) 
 
        val DFPerson = RDDPerson.toDF()
 
        DFPerson.printSchema()
 
        DFPerson.select($"name",$"age").show()
 
    }
 
}

运行结果:

二、自定义schema

        这种方式是通过编程接口(StructType),允许创建一个schema,然后将其应用到RDD[Row]中。相对来说,这种方式的步骤会比较繁琐,但更自由,更灵活。因为有很多时候样例对象(case class)不能提前定义,或者一个文本的数据集的字段对不同的用户来说,需要被解释为不同的字段名,那么通过这种方式可以灵活定义schema。

package com.cjs
 
import org.apache.log4j.{Level, Logger}
import org.apache.spark.SparkConf
import org.apache.spark.sql.{Row, SparkSession}
import org.apache.spark.sql.types._
 
object RDDToDF2 {
    def main(args: Array[String]): Unit = {
        Logger.getLogger("org.apache.spark").setLevel(Level.ERROR)
 
        val conf = new SparkConf()
            .set("spark.sql.warehouse.dir","file:///e:/tmp/spark-warehouse")
            .set("spqrk.some.config.option","some-value")
 
        val ss = SparkSession
            .builder()
            .config(conf)
            .appName("RDD_To_DF2")
            .master("local[2]")
            .getOrCreate()
 
        import ss.implicits._
 
        val schemaString = "name,age"   //1、创建schema所需要的字段名的字符串,用特殊符号连接,如“,”
 
        //2、遍历schema的fileName,将每个fileName封装成StructField对象,实质是定义每一个file的数据类型、属性。 Array[StructField]
        val fields = schemaString.split(",").map(fileName => StructField(fileName, StringType, nullable = true))
        //3、将 Array[StructField]转化成schema
        val schema = StructType(fields)
 
        val sc = ss.sparkContext
        val path = "E:\\IntelliJ Idea\\sparkSql_practice\\src\\main\\scala\\com\\cjs\\person3.txt"
        val peopleRDD = sc.textFile(path)
        //4、构建RDD[Row]
        val rowRDD = peopleRDD.map(_.split(",")).map(att=>Row(att(1),att(0).trim))
 
        val peopleDF = ss.createDataFrame(rowRDD, schema)
 
        peopleDF.select($"name",$"age").show()
    }
 
}

运行结果:

posted @ 2019-09-05 15:05  KamShing  阅读(6002)  评论(0编辑  收藏  举报