Spark SQL精华及与Hive的集成(spark sql原理,API,操作外部源数据,SQL函数)

本文深入探讨Spark SQL的原理,包括其在Hadoop上的SQL实现、Spark SQL的前身Shark、Catalyst优化器的工作流程。同时,介绍了Spark SQL的API,如Dataset和DataFrame的使用,以及如何操作外部数据源如Parquet、Hive和RDBMS。此外,还讲解了Spark SQL的内置函数和自定义函数,以及Spark SQL CLI的使用。
摘要由CSDN通过智能技术生成

一.Spark SQL原理

1.SQL on Hadoop

  • SQL是一种传统的用来进行数据分析的标准
    Hive是原始的SQL-on-Hadoop解决方案
    Impala:和Hive一样,提供了一种可以针对已有Hadoop数据编写SQL查询的方法
    Presto:类似于Impala,未被主要供应商支持
    Shark:Spark SQL的前身,设计目标是作为Hive的一个补充
    Phoenix:基于HBase的开源SQL查询

2.spark的前身:shark

Shark的初衷:让hive运行在Spark上

是对HIve的改造,继承了大量的hive代码,给优化和维护带来了大量的麻烦

3.Spark SQL架构

  • Spark SQL是Spark的核心组件之一(2014.4 Spark1.0)
  • 能够直接访问现存的Hive数据
  • 提供JDBC/ODBC接口供第三方工具借助Spark进行数据处理
  • 提供了更高层级的接口方便地处理数据
  • 支持多种操作方式:SQL、API编程
  • 支持多种外部数据源:Parquet、JSON、RDBMS等

在这里插入图片描述

4.Spark SQL运行原理

Catalyst优化器是Spark SQL的核心


sql—逻辑计划树—逻辑计划—优化后的逻辑计划—物理计划—查询物理计划—RDD

Catalyst Optimizer:Catalyst优化器,将逻辑计划转为物理计划

5.Catalyst优化器

(1)逻辑计划

--在people表中找到id为1的人名字
SELECT name FROM
(
    SELECT id, name FROM people
) p
WHERE p.id = 1

逻辑计划:Scan(people)—>Project(id,name)—>Filter(id=1)—>Project(name)

(2)优化

1、在投影上面查询过滤器
2、检查过滤是否可下压

(检查是否先进行过滤,减少数据处理,提高速度)

原计划:Scan(people)—>Project(id,name)—>Filter(id=1)—>Project(name)

Filter下压:Scan(people)—>Filter(id=1)—>Project(id,name)—>Project(name)

(3)物理计划

原计划:Scan(people)—>Project(id,name)—>Filter(id=1)—>Project(name)

Filter下压:Scan(people)—>Filter(id=1)—>Project(id,name)—>Project(name)

合并Projection:Scan(people)—>Filter(id=1)—>Project(name)

物理计划:IndexLoopup return:name

Catalyst进行一个逻辑计划到物理计划的优化,减少代码量

二.Spark SQL API

  • SparkContext
  • SQLContext
    Spark SQL的编程入口
  • HiveContext
    SQLContext的子集,包含更多功能
  • SparkSession(Spark 2.x推荐)
    SparkSession:合并了SQLContext与HiveContext
    提供与Spark功能交互单一入口点,并允许使用DataFrame和Dataset API对Spark进行编程
  • Dataset (Spark 1.6+)
  • DataFrame

1.Dataset

(1)基本概念

特定域对象中的强类型集合

在这里插入图片描述

由上图可知,直接启动spark-shell后会自动创建spark session对象,并命名为spark,所以下面可以直接调用

scala> spark.createDataset(1 to 3).show
+-----+
|value|
+-----+
|    1|
|    2|
|    3|
+-----+

scala> spark.createDataset(List("a","b")).show
+-----+
|value|
+-----+
|    a|
|    b|
+-----+

scala> spark.createDataset(List(("a",1),("b",2))).show
+---+---+
| _1| _2|
+---+---+
|  a|  1|
|  b|  2|
+---+---+


scala> spark.createDataset(sc.makeRDD(List((1,2,3,4),(2,3,4,5)))).show
+---+---+---+---+
| _1| _2| _3| _4|
+---+---+---+---+
|  1|  2|  3|  4|
|  2|  3|  4|  5|

有结构

  • createDataset()的参数可以是:Seq、Array、RDD
  • 上面三行代码生成的Dataset分别是:
    Dataset[Int]、Dataset[(String,Int)]、Dataset[(String,Int,Int)]
  • Dataset=RDD+Schema,所以Dataset与RDD有大部共同的函数,如map、filter等

(2)使用Case Class创建Dataset

package lianxi22

import org.apache.spark.SparkContext
import org.apache.spark.rdd.RDD
import org.apache.spark.sql.{
   Dataset, SparkSession}

object CreateDataSetDemo {
   
  //创建样例类
      case class Point(label:String,x:Double,y:Double)

  def main(args: Array[String]): Unit = {
   
    //TODO:1.创建一个spark session对象
    val spark: SparkSession = SparkSession.builder().master("local[*]")
      .appName("test02")
      .getOrCreate()
    spark
    //导包(spark中的一些方法)
    import spark.implicits._
     val sc: SparkContext = spark.sparkContext
    //TODO:2.创建一个RDD
      val pointRDD: RDD[(String, Double, Double)] = sc.makeRDD(List(("bar",3.0,4.0),("foo",2.0,2.5)))
    //TODO:3.使用spark对象来创建Dataset
  val ds1: Dataset[(String, Double, Double)] = pointRDD.toDS()
    ds1.show()
    //使用RDD使用样例类的方式生产Dataset
    val pointDS: Dataset[Point] = pointRDD.map(x=>Point(x._1,x._2,x._3)).toDS()
    pointDS.show()
  }
}
//输出
+---+---+---+
| _1| _2| _3|
+---+---+---+
|bar|3.0|4.0|
|foo|2.0|2.5|
+---+---+---+

+-----+---+---+
|label|  x|  y|
+-----+---+---+
|  bar|3.0|4.0|
|  foo|2.0|2.5|
+-----+---+---+

对比可知:使用样例类后会变量成为列名

使用Dataset完成orders.csv表的数据加载

package lianxi22

import org.apache.spark.SparkContext
import org.apache.spark.rdd.RDD
import org.apache.spark.sql.{
   Dataset, SparkSession}

object Demo01 extends App {
   
val spark: SparkSession= SparkSession.builder()
  .master("local[*]")
  .getOrCreate()
  import spark.implicits._

   val sc: SparkContext = spark.sparkContext
   val orderFile: RDD[String] = sc.textFile("file:///D:\\Users\\86188\\kb09\\spark1\\src\\data\\orders.csv")
  private val orderDS: Dataset[Order] = orderFile.map(x => {
   
    //"1","2013-07-25 00:00:00","11599","CLOSED"
    //按逗号分隔,并去掉引号
    val fields: Array[String] = x.split(",").map(y => y.replace("\"", ""))
    Order(fields(0), fields(1), fields(2), fields(3))
  }).toDS()
  orderDS.show()

}

case class Order(id:String,date:String,customerId:String,status:String)

2.Dataframe

(1)基本概念

  • DataFrame=Dataset[Row]
  • 类似传统数据的二维表格
  • 在RDD基础上加入了Schema(数据结构信息)
  • DataFrame Schema支持嵌套数据类型
    struct
    map
    array
  • 提供更多类似SQL操作的API

(2)RDD与DataFrame对比

在这里插入图片描述

(3)创建DataFrame及基本操作

package lianxi22

import org.apache.spark.sql.{
   DataFrame,  SparkSession}

object CreateDataFrame extends App {
   
  //TODO:1.创建一个spark session对象
  val spark: SparkSession = SparkSession.builder().master("local[*]")
    .appName("test02")
    .getOrCreate()
  //导包(spark中的一些方法)
  import spark.implicits._
  //TODO:2.通过spark read读取json文件,创建dataframe
  private val jsonDF: DataFrame = spark.read.json("file:///D:\\Users\\86188\\kb09\\spark1\\src\\data\\users.json")
  //TODO:3.DataFrame常用操作
  // 使用show方法将DataFrame的内容输出
  jsonDF.show()
  // 使用printSchema方法输出DataFrame的Schema信息
  jsonDF.printSchema()
  // 使用select方法来选择我们所需要的字段
  jsonDF.select("name").show()

 jsonDF.select(jsonDF("name"),jsonDF("Age")).show()
  // 使用select方法选择我们所需要的字段,并为age字段加1
   jsonDF.select(jsonDF("name"),jsonDF("Age")+1).show()

  jsonDF.select($"name",$"Age").show()
  //  使用filter方法完成条件过滤
jsonDF.filter($"Age">21).show()
  //使用groupBy进行分组,求分组后的总数
  jsonDF.groupBy("Age").count().show()
  //sql()方法执行SQL查询操作
  //把DataFrame注册成一张临时表
  jsonDF.createOrReplaceTempView("people")
  private val df2: DataFrame = spark.sql("select * from people")
df2.show()
  spark.stop()

}
//输出
+----+-------+
| Age|   name|
+----+-------+
|null|Michael|
|  30|   Andy|
|  19| Justin|
+----+-------+

root
 |-- Age: long (nullable = true)
 |-- name: string (nullable = true)

+-------+
|   name|
+-------+
|Michael|
|   Andy|
| Justin|
+-------+

+-------+----+
|   name| Age|
+-------+----+
|Michael|null|
|   Andy|  30|
| Justin|  19|
+-------+----+

+-------+---------+
|   name|(Age + 1)|
+-------+---------+
|Michael|     null|
|   Andy|       31|
| Justin|       20|
+-------+---------+

+--
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值