• [Spark]-结构化数据查询之初识篇


    1.概述

      Spark-SQL是Spark用于处理结构化数据的一个模块.

      它与RDD的优势在于

        对外而言,类SQL语言会有更大的人群适应性.

        对内而言,Spark-SQL的结构化信息,会带来额外的执行优化

      注意一个认识误区,Spark-SQL 不等于 SQL.

        Spark-SQL是Spark用于处理结构化数据的一个模块,SQL仅仅只是Spark-SQL中一部分,而在SQL之外,Spark还有DataFrame,DataSet等等,也是Spark用来处理结构化数据的技术手段

    2.Spark的结构化数据处理方案

      2.1 dataset

         dataset是Spark自1.6+版本后添加一种新的分布式数据集.类似与一个强类型的分布式的Java集合

         它的目的为传统RDD增加结构化(强类型)的支持,依赖更多的来自结构化的信息,为执行计划提供更好的优化.

       2.2 dataframe

        dataframe是dataset<Row>的别名,它是用统一的Row对象(包含列名,数据类型等等)作为强类型的包装,类似与关系型数据库的表概念.

        dataframe相比dataset,在面对外部数据源时会更加方便(不用写强类型定义),比如结构化数据文件等等

      2.3 SQL

        Spark对结构化查询语言(SQL)处理结构化数据的支持.并且完美兼容HiveSQL(事实上,Spark甚至内置了一个Hive引擎)

      这三种只是针对开发者而言的技术手段区分,事实上Spark内部是使用同一种计算引擎处理的.换句话说,我们可以在这三种技术手段之间自由的切换

    2.SparkSession

      SparkSession 是 Spark-SQL的统一入口.一个简单的SparkSession声明如下  

      import org.apache.spark.sql.SparkSession
    
      val spark = SparkSession
        .builder()
        .getOrCreate()
    
      // For implicit conversions like converting RDDs to DataFrames
      import spark.implicits._

    3.DataFrame

     

    import org.apache.spark.sql.SparkSession;
    
      val spark = SparkSession
        .builder()
        .appName("Spark-Sql-DataFrame-App").master("local[2]")
        .getOrCreate();
      import spark.implicits._;
    
      /**
        * 构建一个DF
        *   读取一个本地Json文件(可以是HDFS或任意Hadoop支持的存储系统)
        */
      val peopleDF =  spark.read.json("D:\data\people.json");
    
      /**
        * DF的一些基本操作
        */
      println("******************************** DF的一些基本操作 *************************************")
      //打印架构
      peopleDF.printSchema()
      //打印前10行数据
      peopleDF.show(10)
      //dataFrame依然有RDD的支持(比如持久化机制)
      val peopleCache = peopleDF.filter($"age">0).cache();
      //一个简单的dataFrame查询实例
      peopleCache.filter($"age"< 30).select($"name",$"age").groupBy($"name",$"age").count().show(10)
    
    
      /**
        * DF转SQL的临时表
        * 这样可以非常容易的将一个DF转到SQL层面来处理
        */
      println("******************************** DF转SQL *************************************")
      //类似RDBMS的会话临时表,SparkSession关闭后自动关闭临时表
      peopleCache.createOrReplaceTempView("peopleTmp")
      spark.sql("select name,age,count(1) from peopleTmp where age < 30 group by name,age").show(10)
      //类似RDBMS的全局临时表,可以在跨Session状态下使用
      //全局临时表必须注册在global_temp,且使用时必须包含全名: global_temp.xxxx
      peopleCache.createOrReplaceGlobalTempView("peopleGlobTmp")
      spark.newSession().sql("select name,age,count(1) from global_temp.peopleGlobTmp where age < 30 group by name,age").show(10)
    
      spark.close();

     4.Dataset 

      import org.apache.spark.sql.SparkSession;
    
      val spark = SparkSession
        .builder()
        .appName("Spark-Sql-DataSet-App").master("local[2]")
        .getOrCreate();
    
      import spark.implicits._;
    
      //定义描述DS结构的Person类型
      case class Person(name: String, age: Long)
    
      /**
        * 构建DS
        */
      //从一个Java对象集合中创建DS
      val dsFromScalaCollection = Seq(Person("SuperMan", 20)).toDS();
      //从一个结构化的外部系统中创建DS
      val dsFromLocalSystem_Json = spark.read.format("json").load("D:\data\people.json").na.fill(0,Seq("age")).as[Person];
      //从一个非结构化的外部数据源中创建DS
      val dsFromLocalSystem_Txt = spark.read.textFile("D:\data\people.txt")
        .map(line => line.split(",")).map(columns => Person(columns(0), columns(1).trim.toInt))
      //使用unionByName而不使用union  union:根据模式中的位置解析列(模式中的列位置不一定与数据集中强类型对象中的字段匹配)
      val peopleDS = dsFromScalaCollection.unionByName(dsFromLocalSystem_Txt).unionByName(dsFromLocalSystem_Json)
    
      //数据任意使用,不关心来自什么外部系统(外部系统异构透明)
      peopleDS.filter($"age"< 30).select($"name",$"age").groupBy($"name",$"age").count().show(10)
    
      spark.stop()

    5.Sql

      val spark = SparkSession.builder().appName("SQL-App").master("local[2]").getOrCreate()
      import  spark.implicits._;
      case class Person(name: String, age: Long)
    
      //DS读取非结构化数据至SQL临时表
      spark.read.textFile("D:\data\people.txt")
        .map(line=>line.split(",")).map(columns=>Person(columns(0),columns(1).trim.toLong))
        .createTempView("data_from_txt")
    
      //Sql方式读取数据
      val sql =
        """
          |CREATE TEMPORARY VIEW data_from_json
          |USING org.apache.spark.sql.json
          |OPTIONS (
          |  path "D:\data\people.json"
          |)
        """.stripMargin;
      spark.sqlContext.sql(sql);
      //简单使用
      spark.sqlContext.sql("SELECT * FROM  data_from_json json join data_from_txt txt on json.name = txt.name").show();
    
      spark.close();

    6.Spark-SQL与RDD

      Spark-SQL支持两种方式将一个RDD转换为Dataset.

        使用反射的方式去从一个包含指定类型的RDD中,推导出指定类型的schema

        手动构造一个shema,然后将它应用在一个已存在的编程接口.(这种方式比较繁琐,但这提供了对列和类型都是未知的情况下构造一个Dataset的一个途径)

      6.1 反射推导schema   

            val spark = SparkSession.builder().master("local[2]").appName("RDD2DFDS_App").getOrCreate();
            
            import spark.implicits._;
            
            //反射推导需要定义DS的目标类型
            case class Person(name: String, age: Long)
            //构造出一个RDD
            val rdd = spark.sparkContext.textFile("D:\data\people.txt")
            //RDD TO DF
            val df = rdd
            .map(row => row.split(","))
            .map(columns => Person(columns(0), columns(1).trim.toInt))
            .toDF()
            df.show(10)
            
            spark.close()

      6.2 编程方式写入schema

        当类型无法在执行之前定义时,Dataframe可以按照以下步骤构建出:

          从原始RDD中构建出行(Row)定义

          创建一个StructType(schema的定义),匹配刚才定义的行(Row)的结构

          使用SparkSession提供的createDataFrame方法应用 Schema 到 RDD 的行(Row)  

            val spark = SparkSession.builder().master("local[2]").appName("RDD2DFDS_App").getOrCreate();
            import spark.implicits._;
            
            //一个非结构化的原始RDD
            val rdd = spark.sparkContext.textFile("D:\data\people.txt")
            //原始RDD转RDD[Row]
            val rowRdd = rdd.map(row=>row.split(",")).map(columns=>Row(columns(0),columns(1).trim.toLong))
            //定义schema
            val schema = StructType(
            StructField(name = "name", dataType = org.apache.spark.sql.types.StringType, nullable = true) ::
            StructField(name = "age", dataType = org.apache.spark.sql.types.LongType, nullable = true) :: Nil
            )
            // DF 等于 RDD[Row] + schema
            val df =spark.createDataFrame(rowRdd,schema)
            df.show();
            spark.close()
  • 相关阅读:
    值传递
    抽象类
    面向对象三大特征(二)--继承
    单例设计模式
    神奇的main方法详解
    面向对象的三大特征 ---- 封装
    变量、方法以及静态和非静态
    面向对象编程-类和对象
    数组
    力扣题库刷题(随时记录)
  • 原文地址:https://www.cnblogs.com/NightPxy/p/9259226.html
Copyright © 2020-2023  润新知