Spark SQL介绍 & 特点 & 架构 & SQL on Hadoop介绍

Spark SQL简单介绍 & 为什么需要SQL

切记:Spark不止是单单写SQL那么简单!

  • 为什么需要SQL?
    这是对数据统计分析的一种标准
    关系型数据库,存储的数据量是有限制的:
    [1] 将庞大的数据量使用关系型数据库进行存储,之后进行统计分析 是有一定的难度的
    [2] 三大运营商的BI系统,原来都是基于DB2来做的,但是随着量的越来越大,他们肯定要做类似的升级
    ==> 因此有了云化
      说白了,就是将原来的关系型数据库处理,放到大数据平台上进行处理

  • 那么,由此引出一个问题
    原来基于关系型数据库做的那些东西,所使用的 分析和技巧 是否已经过时了呢?
    其实原来,针对关系型数据库肯定是做了很多优化(针对SQL层面)
    那么对于这些优化,或是分析的过程 是否是过时了呢?
    答案是没有的
    ==> 原来的那些分析技巧,基于不同的分析维度来统计一系列东西 是没有过时的
      只是现在的数据量变大了

  • 云化的过程
    RDBMS ==> Hadoop(广义上的Hadoop,指整个生态)
    最简单的迁移方式就是原来SQL是什么,我们拿过来不改,直接用
    ==> 如果迁移过程中,要去改SQL
      也就意味着所有的业务逻辑,全部需要重新去梳理
      那么,这个所带来的工作量是十分可怕的
    因此迁移的原则是:
      尽可能保留原有的SQL的样子
      ==> 但是这又不太现实
        因为不同的数据库,内置的函数肯定是不一样的
        打个比方:
          原来在DB2的语法,到Hive里面,不支持了怎么办???
          这就需要我们开发大量的UDF去支持原有RDBMS内置的一些函数
    因此,SQL还是需要的;在大数据里面,SQL是非常重要的

  • 关于SQL在企业中的作用
    如果让本地的研发团队,进行如下开发:
    RDD: scala python java ==> RDD
    Hadoop: MapReduce
    是会耗费很大成本的,因为本地的研发团队的研发水平和总部的比起来,肯定是有差距的;哪怕是让总部的来写MR,那也是很费时的;所以相对于,MR或者RDD的表达来说,SQL的表达更容易让人接受与学习

  • 大数据层面
    到了大数据层面来了,那么原有的存储机制是肯定需要改变的
    RDBMS的数据存在哪里呢? ==> 存在文件中 ==> 也就意味着大小是有限制的
    从计算层面来说,也是要改的:
      MySQL用到了哪些计算引擎
      对于大数据来说是分布式的计算框架(比如说MR、Spark)
    因此在迁移的过程中,storage + compute 是需要进行改动的,但是对于SQL我们最好是别动

Hive受欢迎(很多公司拿Hive来做数据仓库,大数据界 SQL的一个事实上的标准),所以 说白了SQL简单易用面广
针对page_views.dats使用Hive:
  table(tablename + columns)
  ==> 定义一张表,columns里包含了字段名称、类型等等
    select * from xxx where condition
如果使用RDD编程或MR进行编程,就很麻烦了,是使用SQL更加方便

建议:
以后在工作中,能使用DataFrame或是DataSet这种高级的API来操作就使用它们来操作

SQL on Hadoop

Hadoop生态当中,有很多框架是支持SQL的,这些框架统称为SQL on Hadoop

  • Hive(* 非常重要,用的比较多):
    Facebook开源的一套框架
    现在支持的引擎:MapReduce/Tez/Spark
    原理:SQL ==转换==> 底层的作业
       MapReduce转换成MapReduce作业
       Tez转换成Tez作业
       Spark转换成Spark作业
    metastore
       梳理出metastore里整个体系内的表的UML图 很重要!!!
       理解metastore内的表结构
       ==> 可以做数据地图
         根据这张地图,我们可以知道集群上面所有的数据存储量
         比如,哪个业务占了多少存储空间,我们可以使用HDFS shell命令进行查看
         但是这样太麻烦,最好的是通过可视化,进行动态的展示,
         通过这种方式,我们很明显可以知道最近存储量增加了多少
         但是这些信息如何获取呢?
         ==> 必然是要去metastore里进行获取的
       ==> 很多SQL on Hadoop都是共用metastore的
         我们Hive里创建的表,我们使用Spark SQL也可以访问、Presto也可以访问
         因为它们之间是共用一套metastore的
    Hive现在的执行速度和原来对比,已经有了很大的提升

  • Impala:
    Cloudera公司的;为了解决Hive里面交互式查询,速度比较慢的问题;也可以与Hive共享一套metastore
    Impala所推荐的存储格式是parquet
    ==> 但是我们通常的格式是文本格式,为了更好在Impala里进行使用,是需要一步转换的
      我们使用Spark SQL是可以很好的将文本格式转换成parquet格式的
    Impala与CM配合起来进行使用的,但是Impala占用资源很高,比较吃Memory

  • Presto
    京东用的很多,有京东的开源版本

  • Shark
    早期的,现在已经没有了;Spark SQL的前身 伯克利自己的

  • Drill
    这个东西,现在前景不错
    我们可以借助Drill的思想,使用Spark实现的一套整合多源数据的项目(思想很重要)

  • Phoenix:
    Spark与Phoenix对接,采用外部数据源的方式:

    val df = sqlContext.read.format(
          "org.apache.phoenix.spark", 
          Map("table" -> "TABLE1", "zkUrl" -> "phoenix-server:2181")
        ).load

    Hive关联HBase去查询,不建议!!!

通过官网解读Spark SQL & 特点

官网:http://spark.apache.org/sql/
官网对于Spark SQL的解读:
Spark SQL is Apache Spark’s module for working with structured data.
Spark的一个子模块,主要功能是用于处理结构化数据

自己的理解:

  • not-so-secret truth
  • is not about SQL
  • about more than SQL

Spark SQL它不仅是SQL,它是超出SQL的

特点:

  1. Integrated
    Seamlessly mix SQL queries with Spark programs.
    在Spark程序里面,能够和多种复杂的SQL查询无缝对接,Spark SQL能够让我们在Spark程序里面去查询结构化的数据,既可以使用SQL,也可以使用DataFrame API

  2. Uniform Data Access
    Connect to any data source the same way.
    统一的数据访问,能够连接到好多的外部数据源上去 使用类似的方式;DataFrame 和 SQL 都支持一种通用的方式去访问各种数据源,包括Hive, Avro, Parquet, ORC, JSON, and JDBC等等,也可以Join这些数据,跨数据源进行Join。比如:将Hive的数据与Parquet的数据进行Join

  3. Hive Integration
    Run SQL or HiveQL queries on existing warehouses.
    Hive的集成性;能够运行SQL或者Hive SQL的查询 在已经存在的数据仓库上面;这点也是很重要的:比如,已经存在的数据仓库,原来就是使用Hive来实现的,那么现在可以使用Spark SQL来做对接

  4. Standard Connectivity
    Connect through JDBC or ODBC.
    标准的数据连接,举例:
    使用Spark SQL,我们把Thrift server起起来之后,
    我们后面的BI系统,就可以通过JDBC的方式进行访问
    ==> 这里会涉及到一个问题:
      Thrift server如何做一些优化
      否则 咣咣咣的上来 服务不挂才怪 这是重点!!!

Spark SQL介绍

官网网址:http://spark.apache.org/docs/latest/sql-programming-guide.html

the interfaces provided by Spark SQL provide Spark with more information about the structure of both the data and the computation being performed.
提供的接口,能够提供给Spark更多的information
如何理解with more information??
==> 更多体现在schema
  有schema了,我们就知道列名、数据类型等
  有了数据类型,压缩…等就引出来了
  
本质上,Spark SQL是使用了额外的信息去做了一些优化的操作,因此必然很多的信息是借助schema过来的
当我们去计算一个结果的时候,类似的执行引擎就会被我们使用,其实就是Catalyst

使用:
整个Spark的一个入口点:SparkSession ==> 所有的东西通过SparkSession来进行获取就行了
Spark SQL里有两个入口:

  • SQLContext ==> 不支持Hive
  • HiveContext ==> 支持Hive;继承了SQLContext

可以通过下列例子进行学习:examples/src/main/scala/org/apache/spark/examples/sql/SparkSQLExample.scala

Spark SQL 的 cache测试

网址:http://spark.apache.org/docs/latest/sql-programming-guide.html#caching-data-in-memory

Spark SQL可以cache tables,使用基于内存的列式存储方式:
1. spark.catalog.cacheTable(“tableName”)
2. dataFrame.cache()

在SQL中使用cache

spark-sql (default)>cache table emp;
spark-sql (default)>cache table dept;

在web ui界面的Storage界面立刻可以看到,与Spark Core对比:

  • Core中是lazy机制的
  • SQL中是eager机制的

注意,cache之后,去执行上述的join操作:
spark-sql (default)>select * from emp e join dept d on e.deptno=d.deptno
通过web ui去对比观察没有cache之前的join操作,input的大小有区别,因为cache之后,从内存中读取了

清除cache

spark-sql (default)>uncache table emp;
spark-sql (default)>uncache table dept;

在web ui界面的Storage界面立刻可以看到,没有想关信息了

Hive Tables

网址:http://spark.apache.org/docs/latest/sql-programming-guide.html#hive-tables
Spark SQL也能够支持 直接从Hive里面来读和写数据除了上述那样写SQL,我们还可以使用API方式进行操作:

$>spark-shell --master local[2] --jars ~/software/mysql-connector-java-5.1.27-bin.jar
scala>spark.table("emp").show

对官网的解读:
Spark SQL也能够支持 直接从Hive里面来 读和写 数据。因为Hive有非常多的dependencies,而这些dependencies是并没有被包含到我们的默认的Spark distribution这个包里的。也就是说我们编译出来那个包是没有这些的。如果Hive的这些依赖能够被在classpath中被找到,Spark是能够自动得加载进来的。也就说只要我们配置了HIVE_HOME之类的,spark里面是不需要hive的那些东西的。注意,hive的dependencies需要在每个worker节点上都有,这样我们才可以去访问hive的那些序列化和反序列化的东西。配置hive,需要将hive-site.xml、core-site.xml、hdfs-site.xml都丢到spark得到conf目录下来其实在生产上,是不需要core-site.xml、hdfs-site.xml这些配置文件的,因为要跑在yarn上面,已经指定了yarn的目录了,自己已经能找得到。当我们用Hive工作的时候,需要实例化一个SparkSession支持Hive support,这样才能够持久化到Hive的metastore里去,支持Hive的序列化和反序列化,用户如果在生产上没有对Hive进行部署,仍然能够开启Hive support。

提出问题:
生产上如果没有安装Hive,对使用Spark SQL有没有关系??
答案是:是没有关系
我们真正需要的是hive-site.xml ==> 这个名字也是可以改的
我们只需要能够访问到metasotre就可以了 ==> 说白了就配置一个元数据就够了

如果工作中没有hive-site.xml,那么context会自动创建一个 metastore_db 在当前的目录下面
创建数据仓库指向spark.sql.warehouse.dir
工作中是不会这样用的

val spark = SparkSession
  .builder()
  .appName("Spark Hive Example")
  .config("spark.sql.warehouse.dir", warehouseLocation)
  .enableHiveSupport()                  //如果想访问Hive的话,就必须指定这句话;没有这个拿不到Hive相关的东西的
  .getOrCreate()

总结:
使用Spark SQL整合Hive,对Hive表的数据进行读和写,是不需要Hive的安装部署,仅仅需要一个metastore的一个配置信息

Spark SQL 架构 & 通过执行计划进行分析

结合下图进行分析:
这里写图片描述

  1. SQL Query、DataFrame上述的都是Spark SQL外面的东西
  2. 进来之后,需要解析未解析的逻辑执行计划
    比如说:SQL写的对不对,这个字段在表里面有没有,写的表到底有没有
    这些东西都在Schema Catalog里面进行获取查询
  3. 拿到之后变成一个逻辑执行计划
  4. 之后成为一个物理的执行计划
  5. 最终基于成本的CBO的模式,给它选择出来就行了

通过执行计划分析:

$>spark-sql --master local[2] --jars ~/software/mysql-connector-java-5.1.27-bin.jar
spark-sql (default)>create table aa(key string, value string);      //创建一张表
// 通过执行计划查看Spark SQL的执行过程  自己和自己join
spark-sql (default)>explain extended select a.key*(4+5),b.value from aa a join aa b on a.key=b.key and a.key>10;

解析逻辑执行计划 对应图中未解析的逻辑查询计划
== Parsed Logical Plan ==
'Project [unresolvedalias(('a.key * (4 + 5)), None), 'b.value]  // Project是投影,输出的2个字段
+- 'Join Inner, (('a.key = 'b.key) && ('a.key > 10))            // InnerJoin 这里是我们的条件
   :- 'SubqueryAlias a
   :  +- 'UnresolvedRelation `aa`       // 因为有个join 有两张表 未解析出来的表aa 现在只是第一步 只知道aa是个字符串
   +- 'SubqueryAlias b
      +- 'UnresolvedRelation `aa`       // 因为有个join 有两张表 未解析出来的表aa 现在只是第一步 只知道aa是个字符串

分析逻辑执行计划 对应图中 经过Catalog的Analyze之后形成了逻辑查询计划
== Analyzed Logical Plan ==
(key * (4 + 5)): int, value: string
Project [(key#37 * (4 + 5)) AS (key * (4 + 5))#41, value#40]    // 最终需要的字段
+- Join Inner, ((key#37 = key#39) && (key#37 > 10))  // 解析出来aa之后,进行Iner Join
   :- SubqueryAlias a
   :  +- SubqueryAlias aa   // 现在已经知道aa这张表从哪里来,采用的是什么序列化和反序列化,取的别名是什么  已经解析出来aa
   :     +- CatalogRelation `default`.`aa`, org.apache.hadoop.hive.serde2.lazy.LazySimpleSerDe, [key#37, value#38]
   +- SubqueryAlias b
      +- SubqueryAlias aa   // 现在已经知道aa这张表从哪里来,采用的是什么序列化和反序列化,取的别名是什么  已经解析出来aa
         +- CatalogRelation `default`.`aa`, org.apache.hadoop.hive.serde2.lazy.LazySimpleSerDe, [key#39, value#40]

// 优化  对应图中 优化的逻辑查询计划
== Optimized Logical Plan ==
Project [(key#37 * 9) AS (key * (4 + 5))#41, value#40]
+- Join Inner, (key#37 = key#39)
   :- Project [key#37]
   :  +- Filter (isnotnull(key#37) && (key#37 > 10))    // 上述一步,是把aa这个表的数据全部拿出来了;
                                                        // 优化过程中先做了个谓词下压,把条件先给压下来了
                                                        // 压下来之后,再做Join,它的性能肯定是要好一些的
   :     +- CatalogRelation `default`.`aa`, org.apache.hadoop.hive.serde2.lazy.LazySimpleSerDe, [key#37, value#38]
   +- Filter ((key#39 > 10) && isnotnull(key#39))
      +- CatalogRelation `default`.`aa`, org.apache.hadoop.hive.serde2.lazy.LazySimpleSerDe, [key#39, value#40]

// 物理执行计划
// InnerJoin转换为SortMergeJoin了  这里 这一步先不用管这么多,了解即可
== Physical Plan ==
*Project [(key#37 * 9) AS (key * (4 + 5))#41, value#40]
+- *SortMergeJoin [key#37], [key#39], Inner
   :- *Sort [key#37 ASC NULLS FIRST], false, 0
   :  +- Exchange hashpartitioning(key#37, 200)
   :     +- *Filter (isnotnull(key#37) && (key#37 > 10))
   :        +- HiveTableScan [key#37], CatalogRelation `default`.`aa`, org.apache.hadoop.hive.serde2.lazy.LazySimpleSerDe, [key#37, value#38]
   +- *Sort [key#39 ASC NULLS FIRST], false, 0
      +- Exchange hashpartitioning(key#39, 200)
         +- *Filter ((key#39 > 10) && isnotnull(key#39))
            +- HiveTableScan [key#39, value#40], CatalogRelation `default`.`aa`, org.apache.hadoop.hive.serde2.lazy.LazySimpleSerDe, [key#39, value#40]
Time taken: 1.218 seconds, Fetched 1 row(s)

普通的字段到了Schema Catalog之后,就知道是从哪个表哪个库里出来的去取了;取出来之后,优化一下,该谓词下压的谓词下压,该过滤的过滤;之后到了物理执行计划,再做MapJoin、broadcastjoin、SortMergeJoin等等的优化。这个过程与Hive没有本质的区别

猜你喜欢

转载自blog.csdn.net/lemonzhaotao/article/details/79470564