一、什么是DataFrame?
DataFrame是一种以RDD为基础的分布式数据集,类似于传统数据库中的二维表格。DataFrame与RDD的主要区别在于,前者带有schema元信息,即DataFrame所表示的二维表数据集的每一列都带有名称和类型。
DataFrame是为数据提供了Schema的视图,可以把它当做数据库中的一张表来对待。DataFrame也是懒执行的,但性能上比RDD要高,主要原因:优化的执行计划,即查询计划通过Spark catalyst optimiser进行优化。
二、什么是DataSet?
DataSet是分布式数据集合。它是Spark 1.6中添加的一个新抽象,是DataFrame的一个扩展。
它提供了RDD的优势(强类型,使用强大的lambda函数的能力)以及Spark SQL优化执行引擎的优点。同时,DataSet也可以使用功能性的转换(操作map,flatMap,filter等等)。
特点:
➢DataSet是DataFrame API的一个扩展,是SparkSQL最新的数据抽象;
➢用户友好的API风格,既具有类型安全检查也具有DataFrame的查询优化特性;
➢用样例类来对DataSet中定义数据的结构信息,样例类中每个属性的名称直接映射到DataSet中的字段名称;
➢DataSet是强类型的。比如可以有DataSet[Car],DataSet[Person]。
➢DataFrame是DataSet的特列,DataFrame=DataSet[Row],所以可以通过as方法将DataFrame转换为DataSet。Row是一个类型,跟Car、Person这些的类型一样,所有的表结构信息都用Row来表示。获取数据时需要指定顺序。
三、SparkSQL核心编程
1、新起点
Spark SQL其实可以理解为对Spark Core的一种封装,不仅仅在模型上进行了封装,上下文环境对象也进行了封装。
在老的版本中,SparkSQL提供两种SQL查询起始点:一个叫SQLContext,用于Spark自己提供的SQL查询;一个叫HiveContext,用于连接Hive的查询。
SparkSession是Spark最新的SQL查询起始点,实质上是SQLContext和HiveContext的组合,所以在SQLContex和HiveContext上可用的API在SparkSession上同样是可以使用的。SparkSession内部封装了SparkContext,所以计算实际上是由sparkContext完成的。
2、DataFrame
Spark SQL的DataFrame API 允许我们使用DataFrame 而不用必须去注册临时表或者生成SQL 表达式。DataFrame API 既有transformation操作也有action操作。
2.1 DataFrame练习
1)创建DataFrame:
scala> val df = spark.read.json("input/user.json")
2)展示:
scala> df.show
+---+-------------+
|age| usersname|
+---+-------------+
| 30|zhangxiaoming|
| 24| zhouxiaolian|
| 23| lixiaohua|
| 26| wangxiaoli|
| 22| chenxiaoyan|
+---+-------------+
3)创建临时视图
scala> df.createTempView("user")
scala> spark.sql("select * from user").show
+---+-------------+
|age| usersname|
+---+-------------+
| 30|zhangxiaoming|
| 24| zhouxiaolian|
| 23| lixiaohua|
| 26| wangxiaoli|
| 22| chenxiaoyan|
+---+-------------+
//筛选年龄
scala> spark.sql("select age from user").show
+---+
|age|
+---+
| 30|
| 24|
| 23|
| 26|
| 22|
+---+
//筛选平均年龄
scala> spark.sql("select avg(age) from user").show
+--------+
|avg(age)|
+--------+
| 25.0|
+--------+
2.2 SQL的基本使用
SQL语法风格是指我们查询数据的时候使用SQL语句来查询,这种风格的查询必须要有临时视图或者全局视图来辅助。
1)读取JSON文件创建DataFrame
//1.读取JSON文件创建DataFrame
scala> val df = spark.read.json("input/user.json")
//2.对DataFrame创建一个临时表
scala> df.createOrReplaceTempView("user")
//3.通过SQL语句实现查询全表
scala> spark.sql("select * from user").show
+---+-------------+
|age| usersname|
+---+-------------+
| 30|zhangxiaoming|
| 24| zhouxiaolian|
| 23| lixiaohua|
| 26| wangxiaoli|
| 22| chenxiaoyan|
+---+-------------+
普通临时表是Session范围内的,如果想应用范围内有效,可以使用全局临时表。使用全局临时表时需要全路径访问,如:global_temp.people。
//5)对于DataFrame创建一个全局表
scala> df.createOrReplaceGlobalTempView("emp")
//6)通过SQL语句实现查询全表
scala> spark.newSession.sql("select * from global_temp.emp").show
+---+-------------+
|age| usersname|
+---+-------------+
| 30|zhangxiaoming|
| 24| zhouxiaolian|
| 23| lixiaohua|
| 26| wangxiaoli|
| 22| chenxiaoyan|
+---+-------------+
3、DSL语法
DataFrame提供一个特定领域语言(domain-specific language, DSL)去管理结构化的数据。可以在Scala, Java, Python 和R 中使用DSL,使用DSL 语法风格不必去创建临时视图了。
1)创建一个DataFrame
2)查看DataFrame的Schema信息
scala> df.printSchema
root
|-- age: long (nullable = true)
|-- usersname: string (nullable = true)
3)只查看"username"列数据
scala> df.select("usersname").show()
+-------------+
| usersname|
+-------------+
|zhangxiaoming|
| zhouxiaolian|
| lixiaohua|
| wangxiaoli|
| chenxiaoyan|
+-------------+
4)查看"username"列数据以及"age+1"数据
//第一种
scala> df.select($"usersname",$"age" + 1).show
+-------------+---------+
| usersname|(age + 1)|
+-------------+---------+
|zhangxiaoming| 31|
| zhouxiaolian| 25|
| lixiaohua| 24|
| wangxiaoli| 27|
| chenxiaoyan| 23|
+-------------+---------+
//第二种
scala> df.select('usersname, 'age + 1).show()
+-------------+---------+
| usersname|(age + 1)|
+-------------+---------+
|zhangxiaoming| 31|
| zhouxiaolian| 25|
| lixiaohua| 24|
| wangxiaoli| 27|
| chenxiaoyan| 23|
+-------------+---------+
//
scala> df.select('usersname, 'age + 1 as "newage").show()
+-------------+------+
| usersname|newage|
+-------------+------+
|zhangxiaoming| 31|
| zhouxiaolian| 25|
| lixiaohua| 24|
| wangxiaoli| 27|
| chenxiaoyan| 23|
+-------------+------+
5)查看"age"大于"30"的数据
scala> df.filter($"age">25).show
+---+-------------+
|age| usersname|
+---+-------------+
| 30|zhangxiaoming|
| 26| wangxiaoli|
+---+-------------+
6)按照"age"分组,查看数据条数
scala> df.groupBy("age").count.show
+---+-----+
|age|count|
+---+-----+
| 26| 1|
| 22| 1|
| 30| 1|
| 23| 1|
| 24| 1|
+---+-----+