Spark Sql实战详解

Spark SQL

Spark SQL是构建在Spark RDD之上的一款ETL(Extract Transformation Load)工具,这类似于构建在MapReduce之上的1.x版本的Hive。同Spark RDD的不同之处在于Spark SQL的API可以给Spark计算引擎提供更多的信息(计算数据结构、转换算子),Spark计算引擎可以根据Spark SQL提供的信息优化底层计算任务。目前为止,Spark SQL提供了两种风格的交互式API:Dataset API/SQL脚本

Dataset API:加强版的RDD操作,例如支持map、flatMap、filter等算子,同时还支持select、where、groupBy、cube等SQL语句,使用者在操作数据的时候必须知道所操作数据的类型,因此通常将这种API操作称为strong-type操作。

val wordPairRDD = spark.sparkContext.textFile("file:///D:/demo/words")
.flatMap(_.split("\\s+"))
.map((_, 1))
//将RDD变成Dataset
wordPairRDD.toDS()
    .groupByKey(pair=>pair._1)
    .agg(typed.sum[(String,Int)](t=>t._2).name("total")) 
    .show()

SQL脚本:使用者无需关注底层 Dataset API,所有的操作类型都是基于命名列类型,在操作数据的时候不必关心所操作数据的类型,因此通常将这种操作称为untyped操作

word num
a    1
b    1
a    1
select sum(num) from t_words groupBy word

参考:http://spark.apache.org/docs/latest/sql-programming-guide.html

Spark SQL研究的主要对象是Dataset/Dataframe(加强版本的RDD)。Dataset是一个分布式的数据集合,在Spark 1.6版本中提供一个新的接口,Dataset提供RDD的优势(强类型,使用强大的lambda函数)以及具备了Spark SQL执行引擎的优点。Dataset可以通过JVM对象构建,然后可以使用转换函数(例如:map、flatMap、filter等算子),目前Dataset API对Scala和Java语言支持比较友好,对Python语言的支持还不算完备。

DataFrame是命名列的数据集-特殊的Dataset,它在概念上等价于关系型数据库,DataFrame可以从很多地方来构建,比如结构化数据文件(json、csv等)、hive中的表(遗留系统对接)或者外部数据库,使用Dataset[Row]的数据集,可以理解DataFrame就是一个Dataset[Row]。

快速入门

<dependency>
    <groupId>org.apache.spark</groupId>
    <artifactId>spark-sql_2.11</artifactId>
    <version>2.4.3</version>
</dependency>

SQL脚本

//1.创建sparksession对象
val spark = SparkSession.builder().appName("word count")
.master("local[6]")
.getOrCreate()
//2.导入常见的隐式转换|增强 将RDD转换为Dataframe/Dataset
import spark.implicits._
spark.sparkContext.setLogLevel("FATAL") //关闭日志信息
//创建RDD
val wordPairRDD = spark.sparkContext.textFile("file:///D:/demo/words")
.flatMap(_.split("\\s+"))
.map((_, 1))
//将RDD转换为Dataframe
val wordDataframe = wordPairRDD.toDF("word", "num")
//将wordDataframe注册为一个t_words表
wordDataframe.createOrReplaceTempView("t_words")
//写SQL脚本查询t_words
spark.sql("select word,sum(num) total from t_words group by  word order by total desc")
.show()
//3.关闭sparksession对象
spark.stop()//close

命名列-API

//1.创建sparksession对象
val spark = SparkSession.builder().appName("word count")
.master("local[6]")
.getOrCreate()
//2.导入常见的隐式转换|增强 将RDD转换为Dataframe
import spark.implicits._
spark.sparkContext.setLogLevel("FATAL") //关闭日志信息
//创建RDD
val wordPairRDD = spark.sparkContext.textFile("file:///D:/demo/words")
.flatMap(_.split("\\s+"))
.map((_, 1))
//将RDD变成Dataframe
import org.apache.spark.sql.functions._
wordPairRDD.toDF("word","num")
.groupBy($"word")
.agg(sum($"num") as "total")
.orderBy($"total" desc)
.show()
//3.关闭sparksession对象
spark.stop()//close

强类型-typed-不推荐

//1.创建sparksession对象
val spark = SparkSession.builder().appName("word count")
.master("local[6]")
.getOrCreate()
//2.导入常见的隐式转换|增强 将RDD转换为Dataframe
import spark.implicits._
spark.sparkContext.setLogLevel("FATAL") //关闭日志信息
//创建RDD
val wordPairRDD = spark.sparkContext.textFile("file:///D:/demo/words")
.flatMap(_.split("\\s+"))
.map((_, 1))
//将RDD变成Dataset
wordPairRDD.toDS()
.groupByKey(pair=>pair._1)
.agg(typed.sum[(String,Int)](t=>t._2).name("total"))
.rdd
.sortBy(_._2,false,3)
.toDF("word","total")
.show()
//3.关闭sparksession对象
spark.stop()//close

Dataset和DataFrame构建

Dataset√

Dataset是一个特殊的RDD(增强版本的RDD),与RDD的不同在于Spark SQL自己维护了一套序列化和反序列化规范,规避在计算过程中因为多次序列化对计算节点的性能损耗,由于Spark SQL提倡untyped的操作,使用者无需关注所操作数据的类型,只需提供针对命名列操作的算子即可,从而提升计算节点的计算性能。

rdd

> sc.textFile("hdfs://...").flatMap(_.split("\\s+")).map((_,1)).reduceByKey(_+_)

dataset

> val wordPairRDD = spark.sparkContext.textFile("file:///D:/demo/words")
      .flatMap(_.split("\\s+"))
      .map((_, 1))
> wordPairRDD.toDF("word","num") //无需知道所操作数据类型,只需提供列名
        .groupBy($"word")
        .agg(sum($"num") as "total")
        .orderBy($"total" desc)
        .show()
  • case-class
case class Person(id:Int,name:String,age:Int,dept:Int)
List(Person(1,"zs",18,1),Person(2,"ls",18,1)).toDS().show()
+---+----+---+----+
| id|name|age|dept|
+---+----+---+----+
|  1|  zs| 18|   1|
|  2|  ls| 18|   1|
+---+----+---+----+
  • tuple元组
 List((1,"zs",18,1),(2,"ls",18,1)).toDS().show()
+---+---+---+---+
| _1| _2| _3| _4|
+---+---+---+---+
|  1| zs| 18|  1|
|  2| ls| 18|  1|
+---+---+---+---+
  • json数据
case class User(id:BigInt,name:String,age:Long,dept:Long)
spark.read.json("file:///D:/demo/json").as[User]
.show()
  • rdd(略)

RDD中的元素必须是元组或者是case-class才可以直接通过toDS()方法创建

Data Frame √

DataFrame是命名列的数据集,它在概念上等价于关系型数据库。DataFrame可以从很多地方来构建,比如说结构化数据文件、hive中的表或者外部数据库,使用Dataset[row]的数据集,可以理解DataFrame就是一个Dataset[Row]。

  • case-class
List(Person(1,"zs",18,1),Person(2,"ls",18,1)).toDF().show()
  • tuple元组
List((1,"zs",18,1),(2,"ls",18,1)).toDF("id","name","age","dept").show()
  • json数据
spark.read.json("file:///D:/demo/json")
.show()
  • RDD 创建

    • RDD[Row]类型
    val rowRDD:RDD[Row] = spark.sparkContext.makeRDD(List((1, "zs", 18, 1), (2, "ls", 18, 1)))
    .map(t => Row(t._1, t._2, t._3, t._4))
    
    val schema = new StructType()
    .add("id",IntegerType)
    .add("name",StringType)
    .add("age",IntegerType)
    .add("dept",IntegerType)
    
    spark.createDataFrame(rowRDD,schema)
    .show()
    
    • RDD[Javabean]
    public class Student implements Serializable {
         
        private Integer id;
        private String name;
        private Integer age;
        private Integer dept;
    
        public Student() 
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值