大数据之sparkSql学习之原理,DataFrame,DataSet及idea代码开发

sparkSql学习之原理,DataFrame,DataSet及idea代码开发
1 目标
  • 1、掌握sparksql原理
  • 2、掌握DataFrame和DataSet数据结构和使用方式
  • 3、掌握sparksql的应用程序开发
2、sparksql概述
2.1 sparksql前世今生
  • shark是专门为spark准备的大规模数据仓库系统
  • shark继承了hive大且复杂的代码,同时它也依赖于spark的版本
  • 后期我们发现hive的复杂的代码逻辑限制了shark的发展
  • 最后终止了对shark开发,把重点转移到了sparksql上
2.2 sparksql是什么
  • Spark SQL is Apache Spark’s module for working with structured data.
  • sparksql是apache spark的一个处理结构化数据的模块。
  • 它提供了一个编程抽象叫做DataFrame并且作为分布式SQL查询引擎的作用。
3、sparksql四大特性
  • 1、易整合
    • 可以将sparksql与spark应用程序进行混合使用
    • 并且可以使用java、scala、python、R等不同语言进行代码开发
  • 2、统一的数据源访问
    • sparksql可以使用一种相同的方式跟不同的外部数据源进行对接
    • SparkSession.read.文件格式(“该格式文件的路径”)
  • 3、兼容hive
    • sparksql支持hivesql的语法
  • 4、支持标准的数据库连接
    • sparksql可以使用标准的jdbc或者是odbc连接上数据库
4、DataFrame
4.1 DataFrame发展
在spark1.3.0之前是没有dataFrame,只有一个schemaRDD,它是直接继承了RDD。在spark1.3.0之后把schema改为dataFrame,但是与schemaRDD有区别:它不在继承自rdd,而是自己实现了rdd的一些方法。后期也可以调用rdd这个方法把一个dataFrame转换成一个rdd。
4.2 DataFrame概念
在Spark中,DataFrame是一种以RDD为基础的分布式数据集,类似于传统数据库的二维表格,DataFrame带有Schema元信息,即DataFrame所表示的二维表数据集的每一列都带有名称和类型,但底层做了更多的优化
4.3 rdd与dataFrame优缺点对比
  • rdd

    • 优点

      • 1、编译时类型安全
        • 就是后期再编译rdd代码的时候,会进行类型检查
      • 2、具有面向对象的编程风格
        • 可以使用对象调用方法的形式去操作对象
    • 缺点

      • 1、数据对象序列化和反序列化性能开销很大

        spark任务是通过分布式计算实现的,后期大量的task在运行的时候,需要进行大量的数据网络传输,数据在传输的时候先要进行序列化,数据内容本身和数据结构信息都需要进行序列化,然后进行反序列化获取得到该对象。
        
      • 2、大量的对象创建会带来大量的GC

        在通过rdd进行编程的时候,可能会构建大量的对象,这些对象的构建都是在jvm堆以内。这个时候需要占用大量的内存空间,后期内存不足了,会导致频繁GC,GC发生时。这个时候所有的任务都是暂停,GC结束之后,任务又继续运行。后期代码要尽量减少GC(垃圾回收)。
        
  • dataFrame

    • dataFrame分别引入了schema(元数据信息)和off-heap(使用不在堆中的内存,直接使用操作系统层面上的内存)

    • 优点

      • 1、它引入了schema,这里的schema就是对数据结构的描述信息,后期这里数据在进行网络传输的时候,只需要序列化数据本身就可以了,数据的结构信息这一块是可以省略掉了,这样一来是减少数据的网络传输。性能是有得到提升。它是解决了rdd中数据对象序列化和反序列化性能开销很大这个缺点。

      • 2、它引入了off-heap,不在使用堆中的内存去构建对象,这个时候是使用操作系统层面上的内存,

        后期jvm堆中的内存就比较充足,不会频繁导致gc。它是解决了rdd大量的对象创建会带来大量的GC这个缺点。

    • 缺点

      • dataFrame分别引入了schema和off-heap解决了rdd的缺点,同时也丢失了rdd的优点
        • 1、dataFrame编译时类型不安全
        • 2、dataFrame不具备面向对象编程的风格
5、读取数据源构建dataFrame
1、读取文本文件构建dataFrame
val df=spark.read.text("/person.txt")
//打印schema
df.printSchema
//展示数据
df.show
2、读取json文件构建dataFrame
val df=spark.read.json("/people.json")
//打印schema
df.printSchema
//展示数据
df.show
3、读取parquet列式存储文件构建dataFrame
val df=spark.read.parquet("/users.parquet")
//打印schema
df.printSchema
//展示数据
df.show
6、DatFrame常用操作
6.1 DSL风格语法
  • dataFrame自身提供了一套api,可以通过这套api去操作它
val rdd1=sc.textFile("/person.txt")
val rdd2=rdd1.map(_.split(" "))
case class Person(id:Int,name:String,age:Int)
val rdd3=rdd2.map(x=>Person(x(0).toInt,x(1),x(2).toInt))

val personDF=rdd3.toDF

personDF.printSchema
personDF.show

personDF.select("name").show
personDF.select($"name").show
personDF.select(col("name")).show
personDF.select("name","age").show

personDF.select($"age"+1).show
personDF.filter($"age" > 30).show
personDF.filter($"age" > 30).count
personDF.groupBy("age").count.show
6.2 SQL风格语法
  • 就是可以把dataFrame看成是一张表

    • 需要把dataFrame注册成一张表

      personDF.createTempView("person")
      
    • SparkSession.sql(sql语句)

    spark.sql("select * from person").show
    spark.sql("select * from person where id=1").show
    spark.sql("select count(*) from person where age >30").show
    
    
7、DataSet
7.1 DataSet是什么
DataSet是分布式的数据集合,Dataset提供了强类型支持,也是在RDD的每行数据加了类型约束。DataSet是在Spark1.6中添加的新的接口。它集中了RDD的优点(强类型和可以用强大lambda函数)以及使用了Spark SQL优化的执行引擎。
7.2 dataSet和dataFrame互相转换
  • 1、dataFrame转换成dataSet

  • 2、dataSet转换成dataFrame

    • val df=ds.toDF
  • 补充

    可以使用dataFrame和dataSet分别调用各自rdd方法,将其转换为一个rdd
    
7.3 如何构建dataSet
  • 1、可以从一个已经存在的scala集合去构建

    val ds=spark.createDataset(List(1,2,3,4))
    val ds=List(1,2,3,4).toDS
    
  • 2、可以从一个已经存在的rdd去构建

    val ds=spark.createDataset(sc.textFile("/words.txt"))
    
  • 3、dataFrame转换成dataSet

    val ds=df.as[强类型]
    
  • 4、通过一个dataSet转换生成一个新的dataSet

    val ds2=ds1.map(x=>x+"_itcast")
    
8、通过IDEA开发sparksql程序实现将RDD转换成DataFrame
  • 1、引入pom依赖

            <dependency>
                <groupId>org.apache.spark</groupId>
                <artifactId>spark-sql_2.11</artifactId>
                <version>2.1.3</version>
            </dependency>
    
8.1 利用反射机制将rdd转换成dataFrame
  • 1、代码开发

    package cn.itcast.sparksql
    
    import org.apache.spark.SparkContext
    import org.apache.spark.rdd.RDD
    import org.apache.spark.sql.{Column, DataFrame, SparkSession}
    
    
    //todo:利用反射将rdd转换成dataFrame(定义样例类)
    
    case class Person(id:Int,name:String,age:Int)
    object CaseClassSchema {
      def main(args: Array[String]): Unit = {
        //1、构建SparkSession
          val spark: SparkSession = SparkSession
                                              .builder()
                                              .appName("CaseClassSchema")
                                              .master("local[2]")
                                              .getOrCreate()
    
        //2、获取sparkContext对象
        val sc: SparkContext = spark.sparkContext
         sc.setLogLevel("warn")
    
        //3、读取文件数据
          val rdd1: RDD[Array[String]] = sc.textFile("E:\\person.txt").map(_.split(" "))
    
        //4、将rdd与样例类进行关联
          val personRDD: RDD[Person] = rdd1.map(x=>Person(x(0).toInt,x(1),x(2).toInt))
    
        //5、将rdd转换成DataFrame
           //手动导入隐式转换
           import  spark.implicits._
          val personDF: DataFrame = personRDD.toDF
    
        //6、打印schema
         personDF.printSchema()
    
    
        //--------------------DSL风格语法--------------start
        personDF.show() //默认展示20条数据,如果一个字符串超过了20个字符,进行截取,保留前20位  zhangsanxxxxxxxxxxxxxxxxxxxxxxxxx
        personDF.show(1)
    
        //获取第一条数据
        println(personDF.first())
        println(personDF.head())
    
        //查询name字段的所有信息
        personDF.select("name").show()
        personDF.select($"name").show()
        personDF.select(new Column("name")).show()
        personDF.select("name","age","id").show()
    
        //把age+1
        personDF.select($"age",$"age"+1).show()
    
        //过滤出年龄大于30的用户
        personDF.filter($"age" >30).show()
        println(personDF.filter($"age" >30).count())
    
        //按照age分组统计个数
        personDF.groupBy("age").count().show()
    
        //--------------------DSL风格语法--------------end
    
        //--------------------SQL风格语法--------------start
         personDF.createTempView("person")
        spark.sql("select * from person").show()
        spark.sql("select count(*) from person").show()
        spark.sql("select * from person where age >30").show()
        spark.sql("select * from person order by age desc").show()
        //--------------------SQL风格语法--------------end
        
        //hivesql ----->底层使用一个sql解析引擎,把hivesql语句翻译成mapreduce代码
    
        //7、关闭
        sc.stop()
        spark.stop()
    
      }
    }
    
    
8.2 通过StructType指定schema 实现将rdd转换成DataFrame
  • 1、代码开发

    package cn.itcast.sparksql
    
    import org.apache.spark.SparkContext
    import org.apache.spark.rdd.RDD
    import org.apache.spark.sql.types.{IntegerType, StringType, StructField, StructType}
    import org.apache.spark.sql.{DataFrame, Row, SparkSession}
    
    //todo:利用StructType指定schema 将rdd转换成dataFrame
    object SparksqlSchema {
      def main(args: Array[String]): Unit = {
        //1、构建SparkSession
        val spark: SparkSession = SparkSession
                                              .builder()
                                              .appName("SparksqlSchema")
                                              .master("local[2]")
                                              .getOrCreate()
    
        //2、构建SparkContext
          val sc: SparkContext = spark.sparkContext
          sc.setLogLevel("warn")
    
        //3、读取文件数据
          val rdd1: RDD[Array[String]] = sc.textFile("E:\\person.txt").map(_.split(" "))
    
        //4、将rdd1与Row对象进行关联
          val rowRDD: RDD[Row] = rdd1.map(x =>Row(x(0).toInt,x(1),x(2).toInt))
    
        //5、指定dataFrame的schema  在指定schema的时候当前字段的类型必要要跟Row对象的数据类型一致
        val schema =
                  StructType(
                      StructField("id", IntegerType, true) ::
                      StructField("name", StringType, false) ::
                      StructField("age", IntegerType, false) :: Nil)
    
    
        val dataFrame: DataFrame = spark.createDataFrame(rowRDD,schema)
    
        //打印schema
         dataFrame.printSchema()
         dataFrame.show()
    
         dataFrame.createTempView("t_person")
        spark.sql("select * from t_person where age >25").show()
    
        sc.stop()
        spark.stop()
      }
    }
    
    
9、sparksql操作hivesql
  • 1、引入依赖

            <dependency>
                <groupId>org.apache.spark</groupId>
                <artifactId>spark-hive_2.11</artifactId>
                <version>2.1.3</version>
            </dependency>
    
  • 2、代码开发

    package cn.itcast.sparksql
    
    import org.apache.spark.sql.SparkSession
    
    //todo:利用sparksql操作hivesql
    object HiveSupport {
      def main(args: Array[String]): Unit = {
           //1、创建SparkSession
            val spark: SparkSession = SparkSession
                                                  .builder()
                                                  .appName("HiveSupport")
                                                  .master("local[2]")
                                                  .enableHiveSupport() //开启对hivesql的支持
                                                  .getOrCreate()
    
    
         //2、通过sparkSession操作hivesql
             //2.1 先创建一个hive表
            //spark.sql("create table user(id string,name string,age int) row format delimited fields terminated by ','")
             //2.2 加载数据到hive表中
            //spark.sql("load data local inpath './data/user.txt' into table user")
             //2.3 查询
            spark.sql("select * from user").show()
    
    
          spark.stop()
      }
    }
    
    
10、使用sparksql操作关系型数据库
10.1 sparksql从mysql加载数据
  • 1、代码开发

    package cn.itcast.sparksql
    
    import java.util.Properties
    
    import org.apache.spark.sql.{DataFrame, SparkSession}
    
    //todo:sparksql从mysql表中加载数据生成dataFrame
    object DataFromMysql {
      def main(args: Array[String]): Unit = {
          //1、创建SparkSession
          val spark: SparkSession = SparkSession.builder().appName("DataFromMysql").master("local[2]").getOrCreate()
    
    
          //2、读取mysql表中数据
             //2.1 定义url连接
           val url="jdbc:mysql://node1:3306/spark"
             //2.2 定义表名
           val table="iplocation"
             //2.3 定义属性
           val properties=new Properties()
           properties.setProperty("user","root")
           properties.setProperty("password","123456")
    
          val mysqlDF: DataFrame = spark.read.jdbc(url,table,properties)
    
           mysqlDF.printSchema()
           mysqlDF.show()
    
    
        spark.stop()
      }
    }
    
    
10.2 sparksql把处理的结果写回到mysql表中
  • 1、代码开发(本地运行)

    package cn.itcast.sparksql
    
    import java.util.Properties
    
    import org.apache.spark.sql.{DataFrame, SparkSession}
    
    //todo:通过sparksql把结果数据写入到mysql表中
    object Data2Mysql {
      def main(args: Array[String]): Unit = {
        //1、创建SparkSession
        val spark: SparkSession = SparkSession
                                    .builder()
                                    .appName("Data2Mysql")
                                    .master("local[2]")
                                    .getOrCreate()
        //2、读取mysql表中数据
        //2.1 定义url连接
        val url="jdbc:mysql://node1:3306/spark"
        //2.2 定义表名
        val table="iplocation"
        //2.3 定义属性
        val properties=new Properties()
        properties.setProperty("user","root")
        properties.setProperty("password","123456")
    
        val mysqlDF: DataFrame = spark.read.jdbc(url,table,properties)
    
        //把dataFrame注册成一张表
          mysqlDF.createTempView("iplocation")
    
        //通过sparkSession调用sql方法
           //需要统计经度和维度出现的人口总数大于1000的记录 保存到mysql表中
          val result: DataFrame = spark.sql("select * from iplocation where total_count >1000")
    
        //保存结果数据到mysql表中
         //mode:指定数据的插入模式
            //overwrite: 表示覆盖,如果表不存在,事先帮我们创建
            //append   :表示追加, 如果表不存在,事先帮我们创建
            //ignore   :表示忽略,如果表事先存在,就不进行任何操作
            //error    :如果表事先存在就报错(默认选项)
         result.write.mode("ignore").jdbc(url,"itcast1",properties)
    
        //关闭
         spark.stop()
      }
    }
    
    
  • 2、代码开发(集群运行)

    package cn.itcast.sparksql
    
    import java.util.Properties
    
    import org.apache.spark.sql.{DataFrame, SparkSession}
    
    //todo:通过sparksql把结果数据写入到mysql表中
    object Data2Mysql {
      def main(args: Array[String]): Unit = {
        //1、创建SparkSession
        val spark: SparkSession = SparkSession
                                    .builder()
                                    .appName("Data2Mysql")
                                    .getOrCreate()
        //2、读取mysql表中数据
        //2.1 定义url连接
        val url="jdbc:mysql://node1:3306/spark"
        //2.2 定义表名
        val table="iplocation"
        //2.3 定义属性
        val properties=new Properties()
        properties.setProperty("user","root")
        properties.setProperty("password","123456")
    
        val mysqlDF: DataFrame = spark.read.jdbc(url,table,properties)
    
        //把dataFrame注册成一张表
          mysqlDF.createTempView("iplocation")
    
        //通过sparkSession调用sql方法
           //需要统计经度和维度出现的人口总数大于1000的记录 保存到mysql表中
          val result: DataFrame = spark.sql("select * from iplocation where total_count >1000")
    
        //保存结果数据到mysql表中
         //mode:指定数据的插入模式
            //overwrite: 表示覆盖,如果表不存在,事先帮我们创建
            //append   :表示追加, 如果表不存在,事先帮我们创建
            //ignore   :表示忽略,如果表事先存在,就不进行任何操作
            //error    :如果表事先存在就报错(默认选项)
         result.write.mode(args(0)).jdbc(url,args(1),properties)
    
        //关闭
         spark.stop()
      }
    }
    
    
    • 1、提交任务

      spark-submit \
      --master spark://node1:7077 \
      --class cn.itcast.sparksql.Data2Mysql \
      --executor-memory 1g \
      --total-executor-cores 4 \
      --jars /export/servers/hive/lib/mysql-connector-java-5.1.35.jar \
      --driver-class-path /export/servers/hive/lib/mysql-connector-java-5.1.35.jar \ original-spark_class15-1.0-SNAPSHOT.jar \
      append \
      itcast100
      
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值