SparkSql学习笔记一

一、SparkSql介绍

1.简介
    Spark SQL是Spark用来处理结构化数据的一个模块,它提供了一个编程抽象叫做DataFrame并且作为分布式SQL查询引擎的作用。
    为什么要学习Spark SQL?
    我们已经学习了Hive,它是将Hive SQL转换成MapReduce然后提交到集群上执行,大大简化了编写MapReduce的程序的复杂性,由于MapReduce这种计算模型执行效率比较慢。所以Spark SQL的应运而生,它是将Spark SQL转换成RDD,然后提交到集群执行,执行效率非常快!同时Spark SQL也支持从Hive中读取数据。
2.特点
    *容易整合
    *统一的数据访问方式
    *兼容Hive
    *标准的数据连接
3.基本概念
    *DataFrame
        DataFrame(表) = schema(表结构) + Data(表结构,RDD)
            就是一个表 是SparkSql 对结构化数据的抽象
            DataFrame表现形式就是RDD
    
        DataFrame是组织成命名列的数据集。它在概念上等同于关系数据库中的表,但在底层具有更丰富的优化。DataFrames可以从各种来源构建,
        DataFrame多了数据的结构信息,即schema。
        RDD是分布式的Java对象的集合。DataFrame是分布式的Row对象的集合。
        DataFrame除了提供了比RDD更丰富的算子以外,更重要的特点是提升执行效率、减少数据读取以及执行计划的优化
    *Datasets
        Dataset是数据的分布式集合。Dataset是在Spark 1.6中添加的一个新接口,是DataFrame之上更高一级的抽象。它提供了RDD的优点(强类型化,使用强大的lambda函数的能力)以及Spark SQL优化后的执行引擎的优点。一个Dataset 可以从JVM对象构造,然后使用函数转换(map, flatMap,filter等)去操作。 Dataset API 支持Scala和Java。 Python不支持Dataset API。
4.创建表 DataFrame
    方式一 使用case class 定义表
        val df = studentRDD.toDF
    方式二 使用SparkSession直接生成表
        val df = session.createDataFrame(RowRDD,scheme)
    方式三 直接读取一个带格式的文件(json文件)
        spark.read.json("")
5.视图(虚表)
    普通视图
        df.createOrReplaceTempView("emp")
            只对当前对话有作用
    全局视图
        df.createGlobalTempView("empG")
            在全局(不同会话)有效
            前缀:global_temp
6.操作表:
    两种语言:SQL,DSL 
    spark.sql("select * from t ").show
    df.select("name").show 

二、load和save
    1.什么是parquet文件?
        Parquet是列式存储格式的一种文件类型.
        Parquet格式是Spark SQL的默认数据源,可通过spark.sql.sources.default配置
    2.通用的Load/Save函数
        *读取Parquet文件
          

  val usersDF = spark.read.load("/root/resources/users.parquet")


        *查询用户的name和喜爱颜色,并保存
            

usersDF.select($"name",$"favorite_color").write.save("/root/result/parquet")


        *显式指定文件格式:加载json格式
            

val usersDF = spark.read.format("json").load("/root/resources/people.json")spark.read.json()


        *保存的时候,覆盖原来的文件
            

usersDF.select($"name").write.mode("overwrite").save("/root/result/parquet1")


        *将结果保存为表
          

 usersDF.select($"name").write.saveAsTable("table1")


    3.Parquet文件
        *Spark SQL提供支持对于Parquet文件的读写,也就是自动保存原始数据的schema
          

                读取json文件
                val empJson = spark.read.json("/root/data/emp.json")
                将数据保存为parquet格式
                empJson.write.parquet("/root/data/parquet")
                重新读取Parquet文件
                val empParquet = spark.read.parquet("/root/data/parquet")
                创建临时视图
                empParquet.createTempView("emp")
                查询
                spark.sql("select * from emp").show


        *scheme的合并
            Parquet支持Schema evolution(Schema演变,即:合并)。用户可以先定义一个简单的Schema,
            然后逐渐的向Schema中增加列描述。通过这种方式,用户可以获取多个有不同Schema但相互兼容的Parquet文件。
            
          

            val def1 = sc.makeRDD(1 to 5).map(i => (i,2*i)).toDF("single","double")
            df1.write.parquet("/root/test/key=1")
            val def2 = sc.makeRDD(6 to 10).map(i => (i,3*i)).toDF("single","triple")
            df2.write.parquet("/root/test/key=2")
            val df3 = spark.read.option("meugeScheme","true").parquet("/root/test/")
                df3.printScheme()


    4.JDBC
        

import org.apache.log4j.{Level, Logger}
        import org.apache.spark.sql.{DataFrame, SparkSession}
        import java.util.Properties
        object LoadAndSaveDemo {
          Logger.getLogger("org.apache.spark").setLevel(Level.OFF)
          def main(args: Array[String]): Unit = {
            val spark = SparkSession.builder().master("local[*]").getOrCreate()
            import spark.implicits._
            val jdbcDL: DataFrame = spark.read.format("jdbc").options(Map(
              "url" -> "jdbc:mysql://localhost:3306/test",
              "driver" -> "com.mysql.jdbc.Driver",
              "dbtable" -> "user",
              "user" -> "root",
              "password" -> "123456"
            )).load()
            //jdbcDL.show()

            jdbcDL.select("name").show()
            //jdbcDL.write.format("json").save("d:/data/save/out1")
            //jdbcDL.write.save("")
            //存储到jdbc
            val prop = new Properties()
            prop.put("user","root")
            prop.put("password","123456")
            //jdbcDL.write.mode("append").jdbc("jdbc:mysql://localhost:3306/test","user2",prop)

            spark.stop()
          }

        }


    5.Hive Table
        HIve 2.x 推荐使用
            

二、代码实现
    1.SparkSql 1.X操作实例 1
        使用case class  和 sql查询
        
      

        import org.apache.log4j.{Level, Logger}
        import org.apache.spark.sql.SQLContext
        import org.apache.spark.{SparkConf, SparkContext}

        object SQLDemo {

          def main(args: Array[String]): Unit = {
            Logger.getLogger("org.apache.spark").setLevel(Level.OFF)
            val conf = new SparkConf().setMaster("local").setAppName("SQLDemo1")
            val sc = new SparkContext(conf)
            //SQLContext是对SparkContext的一个包装 (增强了功能,可以处理结构化数据)
            val sqlC = new SQLContext(sc)

            
            //Dataframe= RDD + Schema
            val lines = sc.parallelize(List("1,tom,99,29","2,marry,98,30","3,jim,98,27"))
            val studentRDD = lines.map(line => {
              val fields = line.split(",")
              val id = fields(0).toLong
              val name = fields(1)
              val fv = fields(2).toDouble
              val age = fields(3).toInt
              Student1(id,name,fv,age)
            })

            //将RDD转换成DataFrame
            //导入隐式转换
            import sqlC.implicits._
            val df = studentRDD.toDF
            //对DataFrame 进行操作
            //使用sql风格的API
            df.registerTempTable("student")
            //sql是一个transformartion
            val result = sqlC.sql("select name,fv from student order by fv desc,age desc")
            //触发action
            result.show()
            sc.stop()


          }
        }

        /**
          * case class 将数据保存到case class
          * case class 的特点:不用new ;实现序列化;模式匹配
          * @param id
          * @param name
          * @param fv
          * @param age
          */
        case class Student1(id:Long,name:String,fv:Double,age:Int)
    


    2.SparkSql 1.X操作实例 2
        使用Row 和 DSL语法
      

        import org.apache.log4j.{Level, Logger}
        import org.apache.spark.{SparkConf, SparkContext}
        import org.apache.spark.sql.SQLContext
        import org.apache.spark.sql.Row
        import org.apache.spark.sql.types._
        object SQLDemo_2 {
          def main(args: Array[String]): Unit = {
            Logger.getLogger("org.apache.spark").setLevel(Level.OFF)
            val conf = new SparkConf().setMaster("local").setAppName("SQLDemo1")
            val sc = new SparkContext(conf)
            //SQLContext是对SparkContext的一个包装 (增强了功能,可以处理结构化数据)
            val sqlC = new SQLContext(sc)

            //Dataframe= RDD + Schema
            val lines = sc.parallelize(List("1,tom,99,29","2,marry,98,30","3,jim,98,27"))
            val studentRDD = lines.map(line => {
              val fields = line.split(",")
              val id = fields(0).toLong
              val name = fields(1)
              val fv = fields(2).toDouble
              val age = fields(3).toInt
              Row(id,name,fv,age)
            })

            //不是用对象  创建一个scheme
            //创建一个scheme(元数据)
            val scheme = StructType(
              List(
                StructField("id",LongType),
                StructField("name",StringType),
                StructField("fv",DoubleType),
                StructField("age",IntegerType)

              )
            )
            //RDD关联scheme
            val df = sqlC.createDataFrame(studentRDD,scheme)
            //使用DSL语法 调用DataFrame
            //select是一个tarnsformation
            val selected = df.select("name","fv","age")
            //排序
            //导入隐式转换
            import sqlC.implicits._
            val result = selected.orderBy($"fv" desc ,$"age" asc)
            result.show()
            sc.stop()
          }
        }


        
    3. SparkSql2.x 操作实例
    
        使用SparkSession
    
      

        import org.apache.log4j.{Level, Logger}
        import org.apache.spark.rdd.RDD
        import org.apache.spark.sql.types._
        import org.apache.spark.{SparkConf, SparkContext}
        import org.apache.spark.sql.{DataFrame, Row, SQLContext, SparkSession}

        object SparkSql2_1 {
          Logger.getLogger("org.apache.spark").setLevel(Level.OFF)
          def main(args: Array[String]): Unit = {
            //val session = SparkSession.builder().appName("SparkSql2.1").master("local")
            val session = SparkSession.builder()
              .appName("SQLDemo2x1")
              .master("local[*]").getOrCreate()
            val lines = session.sparkContext.parallelize(List("1,tom,99,29", "2,marry,98,30", "3,jim,98,27"))
            val RowRDD = lines.map(line =>{
              val fields = line.split(",")
              val id = fields(0).toLong
              val name = fields(1)
              val fcValue = fields(2).toDouble
              val age = fields(3).toInt

              Row(id, name, fcValue, age)
            })
            val scheme = StructType(List(
              StructField("id", LongType),
              StructField("name", StringType),
              StructField("fv", DoubleType),
              StructField("age", IntegerType)
            ))

            val df = session.createDataFrame(RowRDD,scheme)
            df.createTempView("student")
            val result = session.sql("SELECT name,fv,age FROM student WHERE age>27 ORDER BY fv DESC,age ASC")
            //Action 实现输出
            result.show()

          }

        }


    4.Sql 实现WordCount
    
        使用SparkSession.read.textFile读取文件
    
        

        import org.apache.log4j.{Level, Logger}
        import org.apache.spark.sql.{Dataset, SparkSession}

        object Sql_wordCount {
          def main(args: Array[String]): Unit = {
            Logger.getLogger("org.apache.spark").setLevel(Level.OFF)
            val session = SparkSession.builder().appName("wordCount").master("local[3]").getOrCreate()
            //隐式转换
            import session.implicits._
            val words: Dataset[String] = session.read.textFile("d:\\data\\word.txt")
            val word = words.flatMap(x =>x.split(" "))

            //临时表
            word.createTempView("word")
            //sql计数
            //session.sql("select value words,count(*) counts from word group by words order by counts desc").show()
            //分组计数
            val grouped = word.groupBy("value")
            grouped.count().show()

            session.stop()
          }

        }

 

阅读更多

没有更多推荐了,返回首页