原文链接:SparkSQL—用之惜之

  SparkSql作为Spark的结构化数据处理模块,提供了非常强大的API,让分析人员用一次,就会为之倾倒,为之着迷,为之至死不渝。在内部,SparkSQL使用额外结构信息来执行额外的优化。在外部,可以使用SQL和DataSet 的API与之交互。本文笔者将带你走进SparkSql的世界,领略SparkSql之诸多妙处。

一、DataSet和DataFrame

  当使用编程语言对结构化数据进行操作时候,SparkSql中返回的数据类型是DataSet/DataFrame,因此开篇笔者就先对这两种数据类型进行简单的介绍。

  Dataset 是分布式的数据集合。是Spark 1.6中添加的一个新接口,是特定域对象中的强类型集合,它可以使用函数或者相关操作并行地进行转换等操作,数据集可以由JVM对象构造,然后使用函数转换(map、flatmap、filter等)进行操作。Dataset 支持Scala和javaAPI,不支持Python API。

  DataFrame是由列组成的数据集,它在概念上等同于关系数据库中的表或R/Python中的data frame,但在查询引擎上进行了丰富的优化。DataFrame可以由各种各样的源构建,例如:结构化数据文件、hive中的表、外部数据库或现有的RDD。

二、SparkSQL基于DataFrame的操作

import org.apache.spark.sql.SparkSession
2val spark = SparkSession
3 .builder()
4 .appName("Spark SQL basic example")
5 .getOrCreate()
6//引入Spark的隐式类型转换,如将RDD转换成 DataFrame
7import spark.implicits._
8val df = spark.read.json("/data/tmp/SparkSQL/people.json")
9df.show() //将DataFrame的内容进行标准输出
10//+---+-------+
11//|age| name|
12//+---+-------+
13//| |Michael|
14//| 19| Andy|
15//| 30| Justin|
16//+---+-------+
17
18df.printSchema() //打印出DataFrame的表结构
19//root
20// |-- age: string (nullable = true)
21// |-- name: string (nullable = true)
22
23df.select("name").show()
24//类似于select name from DataFrame的SQL语句
25
26df.select($"name", $"age" + 1).show()
27//类似于select name,age+1 from DataFrame的SQL语句
28//此处注意,如果对列进行操作,所有列名前都必须加上$符号
29
30df.filter($"age" > 21).show()
31//类似于select * from DataFrame where age>21 的SQL语句
32
33df.groupBy("age").count().show()
34//类似于select age,count(age) from DataFrame group by age;
35
36//同时也可以直接写SQL进行DataFrame数据的分析
37df.createOrReplaceTempView("people")
38val sqlDF = spark.sql("SELECT * FROM people")
39sqlDF.show()

  

三、SparkSQL基于DataSet的操作

  由于DataSet吸收了RDD和DataFrame的优点,所有可以同时向操作RDD和DataFrame一样来操作DataSet。看下边一个简单的例子。

 1case class Person(name: String, age: Long)
2// 通过 case类创建DataSet
3val caseClassDS = Seq(Person("Andy", 32)).toDS()
4caseClassDS.show()
5// +----+---+
6// |name|age|
7// +----+---+
8// |Andy| 32|
9// +----+---+
10
11// 通过基本类型创建DataSet
12importing spark.implicits._
13val primitiveDS = Seq(1, 2, 3).toDS()
14primitiveDS.map(_ + 1).collect()
15// Returns: Array(2, 3, 4)
16
17// 将DataFrames转换成DataSet
18val path = "examples/src/main/resources/people.json"
19val peopleDS = spark.read.json(path).as[Person]
20peopleDS.show()
21// +----+-------+
22// | age| name|
23// +----+-------+
24// |null|Michael|
25// | 30| Andy|
26// | 19| Justin|
27// +----+-------+

  在上边的例子中能够发现DataSet的创建是非常简单的,但是笔者需要强调一点,DataSet是强类型的,也就是说DataSet的每一列都有指定的列标识符和数据类型。下边的列子将进一步介绍DataSet与RDD的交互。

 1import spark.implicits._
2//将RDD转换成DataFrame
3val peopleDF = spark.sparkContext
4 .textFile("examples/src/main/resources/people.txt")
5 .map(_.split(","))
6 .map(attributes=>Person(attributes(0),attributes(1).trim.toInt))
7 .toDF()
8// 将RDD注册为一个临时视图
9peopleDF.createOrReplaceTempView("people")
10//对临时视图进行Sql查询
11val teenagersDF = spark.sql("SELECT name, age FROM people WHERE age BETWEEN 13 AND 19")
12
13// 对teenagersDF 对应的DataFrame进行RDD的算子map操作
14teenagersDF.map(teenager => "Name: " + teenager(0)).show()
15// +------------+
16// | value|
17// +------------+
18// |Name: Justin|
19// +------------+
20
21// 与上一条语句效果一样
22teenagersDF.map(teenager => "Name: " + teenager.getAs[String]("name")).show()
23// +------------+
24// | value|
25// +------------+
26// |Name: Justin|
27// +------------+

  

 

四、SparkSQL操作HIve表

  Spark SQL支持读取和写入存储在Apache HIVE中的数据。然而,由于Hive具有大量的依赖关系,默认情况下这些依赖性不包含在Spark分布中。如果能在classpath路径找到Hive依赖文件,Spark将自动加载它们。另外需要注意的是,这些Hive依赖项须存在于所有Spark的Worker节点上,因为它们需要访问Hive序列化和反序列化库(SerDes),以便访问存储在Hive中的数据。

1import java.io.File
2import org.apache.spark.sql.{Row, SaveMode, SparkSession}
3
4case class Record(key: Int, value: String)
5
6// 设置hive数据库默认的路径
7val warehouseLocation = new File("spark-warehouse").getAbsolutePath
8
9val spark = SparkSession
10 .builder()
11 .appName("Spark Hive Example")
12 .config("spark.sql.warehouse.dir", warehouseLocation)
13 .enableHiveSupport()
14 .getOrCreate()
15
16import spark.implicits._
17import spark.sql
18
19//创建hive表,导入数据,并且查询数据
20sql("CREATE TABLE IF NOT EXISTS src (key INT, value STRING) USING hive")
21sql("LOAD DATA LOCAL INPATH 'examples/src/main/resources/kv1.txt' INTO TABLE src")
22sql("SELECT * FROM src").show()
23
24// +---+-------+
25// |key| value|
26// +---+-------+
27// |238|val_238|
28// | 86| val_86|
29// |311|val_311|
30// ...
31
32//对hive表数据进行聚合操作
33sql("SELECT COUNT(*) FROM src").show()
34// +--------+
35// |count(1)|
36// +--------+
37// | 500 |
38// +--------+
39
40// sql执行的查询结果返回DataFrame类型数据,支持常用的RDD操作
41val sqlDF = sql("SELECT key, value FROM src WHERE key < 10 ORDER BY key")
42val stringsDS = sqlDF.map {
43 case Row(key: Int, value: String) => s"Key: $key, Value: $value"
44}
45stringsDS.show()
46// +--------------------+
47// | value|
48// +--------------------+
49// |Key: 0, Value: val_0|
50// |Key: 0, Value: val_0|
51// |Key: 0, Value: val_0|
52// ...
53
54// 通过DataFrames创建一个临时视图val recordsDF = spark.createDataFrame((1 to 100).map(i => Record(i, s"val_$i")))
55recordsDF.createOrReplaceTempView("records")
56
57// 查询操作可以将临时的视图与HIve表中数据进行关联查询
58sql("SELECT * FROM records r JOIN src s ON r.key = s.key").show()
59// +---+------+---+------+
60// |key| value|key| value|
61// +---+------+---+------+
62// | 2| val_2| 2| val_2|
63// | 4| val_4| 4| val_4|
64// | 5| val_5| 5| val_5|
65// ...
66
67// 创建一个Hive表,并且以parquet格式存储数据
68sql("CREATE TABLE hive_records(key int, value string) STORED AS PARQUET")
69// 讲DataFrame中数据保存到Hive表里
70val df = spark.table("src")
71df.write.mode(SaveMode.Overwrite).saveAsTable("hive_records")
72sql("SELECT * FROM hive_records").show()
73// +---+-------+
74// |key| value|
75// +---+-------+
76// |238|val_238|
77// | 86| val_86|
78// |311|val_311|
79// ...
80
81// 在指定路径创建一个Parquet文件并且写入数据
82val dataDir = "/tmp/parquet_data"
83spark.range(10).write.parquet(dataDir)
84// 创建HIve外部表
85sql(s"CREATE EXTERNAL TABLE hive_ints(key int) STORED AS PARQUET LOCATION '$dataDir'")
86sql("SELECT * FROM hive_ints").show()
87// +---+
88// |key|
89// +---+
90// | 0|
91// | 1|
92// | 2|
93// ...
94
95// Turn on flag for Hive Dynamic Partitioning
96spark.sqlContext.setConf("hive.exec.dynamic.partition", "true")
97spark.sqlContext.setConf("hive.exec.dynamic.partition.mode", "nonstrict")
98// 通过DataFrame的API创建HIve分区表
99df.write.partitionBy("key").format("hive").saveAsTable("hive_part_tbl")
100sql("SELECT * FROM hive_part_tbl").show()
101// +-------+---+
102// | value|key|
103// +-------+---+
104// |val_238|238|
105// | val_86| 86|
106// |val_311|311|
107// ...
108
109spark.stop()

  当然SparkSql的操作远不止这些,它可以直接对文件快执行Sql查询,也可以通过JDBC连接到关系型数据库,对关系型数据库中的数据进行一些运算分析操作。如果读者感觉不过瘾,可以留言与笔者交流,也可以通过Spark官网查阅相关例子进行学习。下一篇关于Spark的文章,笔者将详细的介绍Spark的常用算子,以满足渴望进行数据分析的小伙伴们的求知的欲望。

更多精彩内容,欢迎扫码关注以下微信公众号:大数据技术宅。大数据、AI从关注开始

 

SparkSQL——用之惜之的更多相关文章

  1. 用TensorFlow教你手写字识别

    博主原文链接:用TensorFlow教你做手写字识别(准确率94.09%) 如需转载,请备注出处及链接,谢谢. 2012 年,Alex Krizhevsky, Geoff Hinton, and Il ...

  2. 踩坑事件:windows操作系统下的eclipse中编写SparkSQL不能从本地读取或者保存parquet文件

    这个大坑... .... 如题,在Windows的eclipse中编写SparkSQL代码时,编写如下代码时,一运行就抛出一堆空指针异常: // 首先还是创建SparkConf SparkConf c ...

  3. sparksql udf的运用----scala及python版(2016年7月17日前完成)

    问:udf在sparksql 里面的作用是什么呢? 答:oracle的存储过程会有用到定义函数,那么现在udf就相当于一个在sparksql用到的函数定义: 第二个问题udf是怎么实现的呢? regi ...

  4. spark-sql性能测试

    一,测试环境       1) 硬件环境完全相同:              包括:cpu/内存/网络/磁盘Io/机器数量等       2)软件环境:              相同数据       ...

  5. SparkSQL读取Hive中的数据

    由于我Spark采用的是Cloudera公司的CDH,并且安装的时候是在线自动安装和部署的集群.最近在学习SparkSQL,看到SparkSQL on HIVE.下面主要是介绍一下如何通过SparkS ...

  6. SparkSQL(源码阅读三)

    额,没忍住,想完全了解sparksql,毕竟一直在用嘛,想一次性搞清楚它,所以今天再多看点好了~ 曾几何时,有一个叫做shark的东西,它改了hive的源码...突然有一天,spark Sql突然出现 ...

  7. Spark入门实战系列--6.SparkSQL(上)--SparkSQL简介

    [注]该系列文章以及使用到安装包/测试数据 可以在<倾情大奉送--Spark入门实战系列>获取 .SparkSQL的发展历程 1.1 Hive and Shark SparkSQL的前身是 ...

  8. Spark入门实战系列--6.SparkSQL(中)--深入了解SparkSQL运行计划及调优

    [注]该系列文章以及使用到安装包/测试数据 可以在<倾情大奉送--Spark入门实战系列>获取 1.1  运行环境说明 1.1.1 硬软件环境 线程,主频2.2G,10G内存 l  虚拟软 ...

  9. Spark入门实战系列--6.SparkSQL(下)--Spark实战应用

    [注]该系列文章以及使用到安装包/测试数据 可以在<倾情大奉送--Spark入门实战系列>获取 .运行环境说明 1.1 硬软件环境 线程,主频2.2G,10G内存 l  虚拟软件:VMwa ...

随机推荐

  1. JAVA_SE基础——11.Java中的运算符

    在程序设计中,运算符应用得十分广泛,通过运算符可以将两个变量进行任意运算.数学中的"+"."-"."*"."/"运算符同 ...

  2. python time、datetime、random、os、sys模块

    一.模块1.定义模块:用来从逻辑上组织Python代码(变量,函数,类,逻辑:实现一个功能),本质就是.py结尾的python文件(文件名:test.py,对应的模块名:test)包:用来从逻辑上组织 ...

  3. Python扩展模块——调用WindowsAPI(pywin32的简单使用)

    这块使用的比较少,只用到了模拟键盘按键, 调用鼠标比较费事,是通过像素坐标实现的,如果没有特殊需求或万不得已不建议使用 import win32con import win32api win32api ...

  4. js的构造函数共用事例

    在使用构造函数去实现一种功能时,我们有时候往往需要实现这个功能,会因此产生多个堆内对象.这样就会造成堆内存滥用.占用不该占用的空间.为此我们可以利用函数把共用的内容封装起来.放便我们的使用.很多东西其 ...

  5. docker实践

    我的docker 学习笔记2   ps axf docker run -d cyf:sshd /usr/sbin -D   docker  ps docker-enter.sh 686 ps axf ...

  6. JDBC学习笔记 day1

    JDBC的基本概念: JDBC就是java database connectivity,即java数据库连接. JDBC主要完成的几个任务分别为 与数据库建立一个连接 向数据库发送SQL语句 处理数据 ...

  7. SpringBoot 分布式session

    SpringBoot 分布式session实现 1. 什么是分布式session 在集群环境中,不得不考虑的一个问题是用户访问产生的session如何处理.如过不做任何处理,用户将出现频繁俸禄的现象, ...

  8. 错误解决:HibernateSystemException-HHH000142: Javassist Enhancement failed

     今天做项目报了一个错误 错误的原因是: 有级联查询的时候,一对多,多对一配置时要考虑默认延迟加载的问题,需要把延迟加载关闭. 然后就能正确查询出结果了  补充知识: 延迟加载表现在:比如:我们要查询 ...

  9. XSS和CSRF的理解

    声明:转自 http://www.cnblogs.com/hyddd/archive/2009/04/09/1432744.html XSS攻击:跨站脚本攻击(Cross Site Scripting ...

  10. AQS源码阅读笔记(一)

    AQS源码阅读笔记 先看下这个类张非常重要的一个静态内部类Node.如下: static final class Node { //表示当前节点以共享模式等待锁 static final Node S ...