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 ,暂时不想写,心情不好,过段时间再说。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值