3 SparkSQL DataFrame和DataSet

标签:大数据 Spark

3 SparkSQL DataFrame和DataSet

1 概述

Spark SQL 是 Spark 处理结构化数据的一个模块.与基础的 Spark RDD API 不同, Spark SQL 提供了查询结构化数据及计算结果等信息的接口.

2 Datasets and DataFrames

2.1. DataSets

一个 Dataset 是一个分布式的数据集合。 Dataset 是在 Spark 1.6 中被添加的新接口, 它提供了 RDD 的优点(强类型化, 能够使用强大的 lambda 函数)与Spark SQL执行引擎的优点.一个 Dataset 可以从 JVM 对象来 构造 并且使用转换功能(map, flatMap, filter, 等等)

2.2 DataFrame --(表)

一个 DataFrame 是一个 Dataset 组成的指定列.它的概念与一个在关系型数据库或者在 R/Python 中的表是相等的, 但是有很多优化. DataFrames 可以从大量的 sources 中构造出来, 比如: 结构化的文本文件, Hive中的表, 外部数据库, 或者已经存在的 RDDs.

3 Quick Start

3.1 起始点: SparkSession

SparkSession-Spark的一个全新的切入点。
SparkSession是Spark 2.0引如的新概念。SparkSession为用户提供了统一的切入点,来让用户学习spark的各项功能。
在spark的早期版本中,SparkContext是spark的主要切入点,由于RDD是主要的API,我们通过sparkcontext来创建和操作RDD。对于每个其他的API,我们需要使用不同的context。例如,对于Streming,我们需要使用StreamingContext;对于sql,使用sqlContext;对于Hive,使用hiveContext。但是随着DataSet和DataFrame的API逐渐成为标准的API,就需要为他们建立接入点。所以在spark2.0中,引入SparkSession作为DataSet和DataFrame API的切入点,SparkSession封装了SparkConf、SparkContext和SQLContext。为了向后兼容,SQLContext和HiveContext也被保存下来。
  SparkSession实质上是SQLContext和HiveContext的组合(未来可能还会加上StreamingContext),所以在SQLContext和HiveContext上可用的API在SparkSession上同样是可以使用的。SparkSession内部封装了sparkContext,所以计算实际上是由sparkContext完成的。
  
Spark SQL中所有功能的入口点SparkSession==. 要创建一个 SparkSession, 仅使用 SparkSession.builder()就可以了:

import org.apache.spark.sql.SparkSession

val spark = SparkSession
  .builder()
  .appName("Spark SQL basic example")
  .config("spark.some.config.option", "some-value")
  .getOrCreate()

// For implicit conversions like converting RDDs to DataFrames
import spark.implicits._ //(对于隐式转换,如将RDDs转换为DataFrames)这部分必须带上

3.2 创建 DataFrames

在一个 SparkSession中, 应用程序可以从一个 已经存在的 RDD, 从hive表, 或者从 Spark数据源中创建一个DataFrames.

val df = spark.read.json("file:///home/hadoop/app/spark/examples/src/main/resources/people.json")
scala> df.show()
+----+-------+
| age|   name|
+----+-------+
|null|Michael|
|  30|   Andy|
|  19| Justin|
+----+-------+

主要:在Linux填写路径时,如果是本地路径,请在路径前加上:file:// 如:file:///home/hadoop/app/spark/demo.txt
【总结】
将这部分代码打包到Linux服务器上运行
1)master(“local”)部分去掉
2)val df = spark.read().json(file)修改为:
val df = spark.read().json(args(0));
3)执行脚本

/home/hadoop/app/spark/bin/spark-submit \
--class spark.StructedStreaming \
--master spark://hadoop1:7077 \
--executor-memory 1G \
--total-executor-cores 1 \
/home/hadoop/app/spark/files/myspark-1.0-SNAPSHOT.jar file:///home/hadoop/app/spark/examples/src/main/resources/people.json

3.3 无类型的Dataset操作 (aka DataFrame 操作)

    // 这个import很重要($-notation) 
    import spark.implicits._
    // Print the schema in a tree format
    df.printSchema()
    // root
    // |-- age: long (nullable = true)
    // |-- name: string (nullable = true)`
    
    // 选择name列
    df.select("name").show()
    // +-------+
    // |   name|
    // +-------+
    // |Michael|
    // |   Andy|
    // | Justin|
    // +-------+
    
    // 选择name列和age+1列
    df.select($"name", $"age" + 1).show()
    // +-------+---------+
    // |   name|(age + 1)|
    // +-------+---------+
    // |Michael|     null|
    // |   Andy|       31|
    // | Justin|       20|
    // +-------+---------+
    
    // 选择age>21的列
    df.filter($"age" > 21).show()
    // +---+----+
    // |age|name|
    // +---+----+
    // | 30|Andy|
    // +---+----+
    
    // Count people by age
    df.groupBy("age").count().show()
    // +----+-----+
    // | age|count|
    // +----+-----+
    // |  19|    1|
    // |null|    1|
    // |  30|    1|
    // +----+-----+

3.4 编程式使用SQL

// 将 DataFrame 注册为 SQL 临时视图
df.createOrReplaceTempView("people")

val sqlDF = spark.sql("SELECT * FROM people")
sqlDF.show()
// +----+-------+
// | age|   name|
// +----+-------+
// |null|Michael|
// |  30|   Andy|
// |  19| Justin|
// +----+-------+

3.5 全局临时表

全局临时视图与系统保留的数据库global_temp绑定,我们必须使用限定名称来引用它,例如 SELECT * FROM global_temp.view1。

//将dataframe注册为全局临时视图
df.createGlobalTempView("people")

//注意,全局临时表前需要添加“系统保留的数据库” global_temp
spark.sql("select * from global_temp.people").show();

//全局临时视图是跨session
spark.newSession().sql("SELECT * FROM global_temp.people").show();

3.6 Creating Datasets

DataSets与RDD类似,但是,它们不使用Java序列化或Kryo,而是使用专门的编码器来序列化对象以便通过网络进行处理或传输。 虽然编码器和标准序列化都负责将对象转换为字节,但编码器是动态生成的代码,并使用一种格式,允许Spark执行许多操作,如过滤,排序和散列,而无需将字节反序列化为对象。  

【总结】
DataSets采用编码器序列化对象,无需像RDD一样需要反序列化

// 创建类
case class Person(name: String, age: Long)

// 为实例类创建
val caseClassDS = Seq(Person("Andy", 32)).toDS()
caseClassDS.show()
// +----+---+
// |name|age|
// +----+---+
// |Andy| 32|
// +----+---+

// 大多数常见类型的编码器都是通过导入spark.implicits._实现的
val primitiveDS = Seq(1, 2, 3).toDS()
//对每个部分加1
primitiveDS.map(_ + 1).collect() // Returns: Array(2, 3, 4)

// 从json文件中读取数据,创建实例
val path="file:///home/hadoop/app/spark/examples/src/main/resources/people.json"
val peopleDS = spark.read.json(path).as[Person]
peopleDS.show()
// +----+-------+
// | age|   name|
// +----+-------+
// |null|Michael|
// |  30|   Andy|
// |  19| Justin|
// +----+-------+

3.7 与RDD互操作

Spark SQL 支持两种不同的方法用于转换已存在的 RDD 成为 Dataset.
(1)使用反射推断Schema
(2)以编程的方式创建Schema

1 使用反射推断Schema
// 从RDD到DataFrame的隐式转换
import spark.implicits._

// 从文本中创建RDD对象并转换成DataFrame
val path="file:///home/hadoop/app/spark/examples/src/main/resources/people.txt"
val peopleDF = spark.sparkContext
  .textFile(path)
  .map(_.split(","))
  .map(attributes => Person(attributes(0), attributes(1).trim.toInt))
  .toDF()
// 将DataFrame注册为临时视图
peopleDF.createOrReplaceTempView("people")

val teenagersDF = spark.sql("SELECT name, age FROM people WHERE age BETWEEN 13 AND 19")

teenagersDF.map(teenager => "Name: " + teenager(0)).show()
// +------------+
// |       value|
// +------------+
// |Name: Justin|
// +------------+


teenagersDF.map(teenager => "Name: " + teenager.getAs[String]("name")).show()
// +------------+
// |       value|
// +------------+
// |Name: Justin|
// +------------+

// 没有数据集的预定义编码器[MAP[K,V] ],明确定义
implicit val mapEncoder = org.apache.spark.sql.Encoders.kryo[Map[String, Any]]


// row.getValuesMap[T] retrieves multiple columns at once into a Map[String, T]
teenagersDF.map(teenager => teenager.getValuesMap[Any](List("name", "age"))).collect()
// Array(Map("name" -> "Justin", "age" -> 19))

aggregations函数

内置的DataFrame函数提供了常见的聚合函数: count(), countDistinct(), avg(), max(), min()

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值