Spark SQL

SparkSQL特点

  • 写更少的代码
  • 读更少的数据
  • 提供更好的性能(字节码生成技术、SQL优化)

SparkSQL数据抽象

  • DataSet会逐步取代 RDD 和 DataFrame 成为唯一的API接口

  • DataFrame

  • 前身是SchemaRDD。Spark1.3更名为DataFrame。不继承RDD,自己实现了RDD的大部分功能

  • 与RDD类似,DataFrame也是一个分布式数据集:

    • DataFrame可以看做分布式 Row 对象的集合,提供了由列组成的详细模式信息,使其可以得到优化。
    • DataFrame 不仅有比RDD更多的算子,还可以进行执行计划的优化
    • DataFrame更像传统数据库的二维表格,除了数据以外,还记录数据的结构信息,即schema
    • DataFrame也支持嵌套数据类型(struct、array和map)
    • DataFrame API提供的是一套高层的关系操作,比函数式的RDD API要更加友好,门槛更低
    • Dataframe的劣势在于在编译期缺少类型安全检查,导致运行时出错

DataSet

  • 与RDD相比,保存了更多的描述信息,概念上等同于关系型数据库中的二维表

  • 与DataFrame相比,保存了类型信息,是强类型的,提供了编译时类型检查

  • 调用Dataset的方法先会生成逻辑计划,然后Spark的优化器进行优化,最终生成物理计划,然后提交到集群中运行。

  • DataFrame表示为DataSet[Row],即DataSet的子集

  • Row & Schema

  • DataFrame = RDD[Row] + Schema;DataFrame 的前身是 SchemaRDD

  • 三者共性

  • 1、RDD、DataFrame、Dataset都是 Spark 平台下的分布式弹性数据集,为处理海量数据提供便利

  • 2、三者都有许多相同的概念,如分区、持久化、容错等;有许多共同的函数,如map、filter,sortBy等

  • 3、三者都有惰性机制,只有在遇到 Action 算子时,才会开始真正的计算

  • 4、对DataFrame和Dataset进行操作许多操作都需要这个包进行支持, import spark.implicits._

三者区别

  • DataFrame(DataFrame = RDD[Row] + Schema):

    • 1、与RDD和Dataset不同,DataFrame每一行的类型固定为Row,只有通过解析才能获取各个字段的值
    • 2、DataFrame与Dataset均支持 SparkSQL 的操作
  • Dataset(Dataset = RDD[case class].toDS):

    • 1、Dataset和DataFrame拥有完全相同的成员函数,区别只是每一行的数据类型不同;
    • 2、DataFrame 定义为 Dataset[Row]。每一行的类型是Row,每一行究竟有哪些字段,各个字段又是什么类型都无从得知,只能用前面提到的getAS方法或者模式匹配拿出特定字段;
    • 3、Dataset每一行的类型都是一个case class,在自定义了case class之后可以很自由的获得每一行的信息;

SparkSession

  • 在 Spark 2.0 之后:将数据入口点统一到了SparkSession,SparkSession 封装了 SqlContext 及 HiveContext;实现了 SQLContext 及 HiveContext 所有功能;

DataFrame & DataSet的创建

  • 1、由range生成Dataset
  • 2、由集合生成Dataset Dataset = RDD[case class]
  • 3、由集合生成DataFrame DataFrame = RDD[Row] + Schema
  • 4、RDD 转成 DataFrame DataFrame = RDD[Row] + Schema
  • 5、RDD转Dataset Dataset = RDD[case class] | DataFrame = RDD[Row] + Schema
  • 6、从文件创建DateFrame

三者的转换

Action操作

  • 与RDD类似的操作

  • show、collect、collectAsList、head、first、count、take、takeAsList、reduce

  • 与结构相关

  • printSchema、explain、columns、dtypes、col

Transformation操作

  • 与RDD类似的操作

  • map、filter、flatMap、mapPartitions、sample、 randomSplit、 limit、distinct、dropDuplicates、describe

  • 存储相关

  • cacheTable、persist、checkpoint、unpersist、cache

  • Dataset 默认的存储级别是 MEMORY_AND_DISK

  • select相关

  • 列的多种表示、select、selectExpr

    - // 列的多种表示方法。使用""、$""、'、col()、ds("") 
      // 注意:不要混用;必要时使用spark.implicitis._;并非每个表示在所有的地方都有效 
      df1.select($"ename", $"hiredate", $"sal").show 
      df1.select("ename", "hiredate", "sal").show 
      df1.select('ename, 'hiredate, 'sal).show 
      df1.select(col("ename"), col("hiredate"), col("sal")).show 
      df1.select(df1("ename"), df1("hiredate"), df1("sal")).show 

// 下面的写法无效,其他列的表示法有效 
df1.select("ename", "hiredate", "sal"+100).show 
df1.select("ename", "hiredate", "sal+100").show 
// 这样写才符合语法 
df1.select($"ename", $"hiredate", $"sal"+100).show 
df1.select('ename, 'hiredate, 'sal+100).show 

// 可使用expr表达式(expr里面只能使用引号) 
df1.select(expr("comm+100"), expr("sal+100"), expr("ename")).show 
df1.selectExpr("ename as name").show 
df1.selectExpr("power(sal, 2)", "sal").show 
df1.selectExpr("round(sal, -3) as newsal", "sal", "ename").show 
- drop、withColumn、withColumnRenamed、cast(内置函数)
  • where相关 ==filter

  • groupBy相关

  • groupBy、agg、max、min、avg、sum、count(后面5个为内置函数)

  • orderBy相关 ==sort

  • join相关

  - df1.crossJoin(df1).count  // 1、笛卡尔积
  - df1.join(df1, "empno").count // 2、等值连接(单字段)(连接字段empno,仅显示了一次)
    df1.join(df1, Seq("empno", "ename")).show // 3、等值连接(多字段)(连接字段empno、ename,仅显示了一次)
  • 注意 DS在join操作之后变成了DF

  • 集合相关

    • union==unionAll(过期)求并集,不去重、intersect求交 、except求差
  • 空值处理

  • na.fill、na.drop

  • 窗口函数

  • 一般情况下窗口函数不用 DSL 处理,直接用SQL更方便

  • 参考源码Window.scala、WindowSpec.scala(主要)

  • 内建函数

  • http://spark.apache.org/docs/latest/api/sql/index.html

SQL语句

  • SparkSQL与HQL兼容;与HQL相比,SparkSQL更简洁
  • createTempView、createOrReplaceTempView、spark.sql("SQL")

输入 & 输出

  • SparkSQL内建支持的数据源包括:Parquet、JSON、CSV、Avro、Images、BinaryFiles(Spark 3.0)。
  • Parquet是默认的数据源
  - df.write.format("parquet") 
    .mode("overwrite") 
    .option("compression", "snappy") 
    .save("data/parquet") 
  • json文件
  - spark.sql("SELECT * FROM emp").write 
    .format("json") 
    .mode("overwrite") 
    .save("data/json") 
  • CSV文件

  • 注意:如果有中文注意表的字符集,否则会有乱码

  • SaveMode.ErrorIfExists(默认)。若表存在,则会直接报异常,数据不能存入数据库

  • SaveMode.Append。若表存在,则追加在该表中;若该表不存在,则会先创建表,再插入数据

  • SaveMode.Overwrite。先将已有的表及其数据全都删除,再重新创建该表,最后插入新的数据

  • SaveMode.Ignore。若表不存在,则创建表并存入数据;若表存在,直接跳过数据的存储,不会报错

UDF & UDAF

  • UDF(User Defined Function),自定义函数。函数的输入、输出都是一条数据记录

  • UDF可以放到SQL语句的fields部分,也可以作为where、groupBy或者having子句的一部分

  • UDAF(User Defined Aggregation Funcation),用户自定义聚合函数。函数本身作用于数据集合,能够在聚合操作的基础上进行自定义操作(多条数据输入,一条数据输出);类似于在group by之后使用的sum、avg等函数;

  • Spark为所有的UDAF定义了一个父类UserDefinedAggregateFunction 。要继承这个类,需要实现父类的几个抽象方法

  • inputSchema用于定义与DataFrame列有关的输入样式

  • bufferSchema用于定义存储聚合运算时产生的中间数据结果的Schema

  • dataType标明了UDAF函数的返回值类型

  • deterministic是一个布尔值,用以标记针对给定的一组输入,UDAF是否总是生成相同的结果

  • initialize对聚合运算中间结果的初始化

  • update函数的第一个参数为bufferSchema中两个Field的索引,默认以0开始;UDAF的核心计算都发生在

  • update函数中;update函数的第二个参数input: Row对应的并非DataFrame的行,而是被inputSchema投影了的行

  • merge函数负责合并两个聚合运算的buffer,再将其存储到MutableAggregationBuffer中

  • evaluate函数完成对聚合Buffer值的运算,得到最终的结果

  • UDAF分为类型安全和类型不安全两种

访问Hive

  • 最好使用 metastore service 连接Hive;使用直连 metastore 的方式时,SparkSQL程序会修改 Hive 的版本信息;

SparkSQL原理

SparkSQL中的五种 Join 策略 join

  • Broadcast hash join (BHJ)

  • 实现原理是将小表的数据广播到 Spark 所有的 Executor 端,这个广播过程和我们自己去广播数据没什么区别。实现过程:

    • 利用collect算子将小表的数据从Executor端拉取到Driver端
    • 在 Driver 端调用 sparkContext.broadcast 广播到所有 Executor 端
    • 在 Executor 端使用广播的数据与大表进行 Join 操作(实际上是执行map操作)
  • 这种 Join 策略避免了 Shuffle 操作,一般而言比其他join策略执行要快

  • 这种jion满足的条件:

    • 小表的数据必须很小,可以通过 spark.sql.autoBroadcastJoinThreshold 参数来配置,默认是 10MB
    • 如果内存比较大,可以将阈值适当加大
    • 将 spark.sql.autoBroadcastJoinThreshold 参数设置为 -1,可以关闭这种连接方式
    • 只能用于等值 Join,不要求参与 Join 的 keys 可排序
  • Shuffle hash join(SHJ)

  • 当表中的数据比较大,又不适合使用广播,这个时候就可以考虑使用 Shuffle Hash Join

  • Shuffle Hash Join 同样是在大表和小表进行 Join 的时候选择的一种策略。

  • 计算思想:把大表和小表按照相同
    的分区算法和分区数进行分区(根据参与 Join 的 keys 进行分区),这样就保证了 hash 值一样的数据都分发到同一
    个分区中,然后在同一个 Executor 中两张表 hash 值一样的分区就可以在本地进行 hash Join 了。在进行 Join 之
    前,还会对小表的分区构建 Hash Map。Shuffle hash join 利用了分治思想,把大问题拆解成小问题去解决。

  • 要启用 Shuffle Hash Join 必须满足以下条件:

    • 只支持等值 Join
    • spark.sql.join.preferSortMergeJoin 参数必须为 false,该参数自Spark 2.0.0 版本引入的,默认值为true。
    • 小表的大小(plan.stats.sizeInBytes)必须小于 spark.sql.autoBroadcastJoinThreshold * spark.sql.shuffle.partitions(默认值200)
    • 而且小表大小(stats.sizeInBytes)的三倍必须小于等于大表的大小(stats.sizeInBytes),即a.stats.sizeInBytes * 3 < = b.stats.sizeInBytes
  • Shuffle sort merge join (SMJ)

  • 前面两种 Join 策略对表的大小都有条件的,如果参与 Join 的表都很大,这时候就得考虑用 Shuffle Sort Merge Join了。

  • Shuffle Sort Merge Join 的实现思想:

    • 将两张表按照 join key 进行shuffle,保证join key值相同的记录会被分在相应的分区
    • 对每个分区内的数据进行排序
    • 排序后再对相应的分区内的记录进行连接
  • 满足条件:仅支持等值 Join,并且要求参与 Join 的 Keys 可排序

  • Shuffle-and-replicate nested loop join,又称笛卡尔积(Cartesian product join)

  • 两张参与 Join 的表没指定连接条件

  • Broadcast nested loop join (BNLJ)

  • Broadcast nested loop join 在某些情况会对某张表重复扫描多次,效率非常低下

  • 支持等值和不等值 Join,支持所有的 Join 类型

SQL解析过程

  • Spark SQL对SQL语句的处理和关系型数据库类似,即词法/语法解析、绑定、优化、执行。

  • Spark SQL会先将SQL语句解析成一棵树,然后使用规则(Rule)对Tree进行绑定、优化等处理过程。

  • Spark SQL由Core、Catalyst、Hive、Hive-ThriftServer四部分构成:

  • Core: 负责处理数据的输入和输出,如获取数据,查询结果输出成DataFrame等

  • Catalyst: 负责处理整个查询过程,包括解析、绑定、优化等

  • Hive: 负责对Hive数据进行处理

  • Hive-ThriftServer: 主要用于对Hive的访问

  • SparkSQL 上的多种resolve 规则:

  • ResolverRelations。解析表(列)的基本类型等信息

  • ResolveFuncions。解析出来函数的基本信息

  • ResolveReferences。解析引用,通常是解析列名

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值