Spark-SQL的Java实践案例(二)
史上最简单的spark教程
所有代码示例地址:https://github.com/Mydreamandreality/sparkResearch
(提前声明:文章由作者:张耀峰 结合自己生产中的使用经验整理,最终形成简单易懂的文章,写作不易,转载请注明)
(文章参考:Elasticsearch权威指南,Spark快速大数据分析文档,Elasticsearch官方文档,实际项目中的应用场景)
(帮到到您请点点关注,文章持续更新中!)
Git主页 https://github.com/Mydreamandreality
在这里我们继续上一章节SparkSQL的案例啊,没有看上一章节的兄弟萌 点击这里哈https://blog.csdn.net/youbitch1/article/details/88852644
[给卢姥爷上香]
- 上一章节的最开始,我们说为了实现sparkSQL的功能,spark提供了一种全新的RDD叫做
DataFrame,但是我们的SparkSQL返回值一直是DataSet,可能有些兄弟就有点不理解了啊 - Dataset其实是一个分布式的数据收集器
- DataFrame可以从广泛的数据源中构成.比如:结构化的数据文件,Hive的table,外部数据库和RDD
- DataFrame在Scala,Java,Python和R中都支持,在Java中为Dataset
- 这就兄弟萌能理解为啥返回DataSet了吧
- 更具体的东西咱写到后面再分析一波
-
上一章节的最后,我们以编程的方式运行sparkSQL查询,把dataframe注册成为临时表运行SQL语句(也可以称为临时视图)
-
但是它有个很大的问题
- 临时表是当前使用的SQLContext中的临时变量,在我们的的应用退出时这些临时表就不再存在了
- 说白了就是临时视图是session级别的,它会随着session的消息而消失
-
那如果我们想要一个临时视图在所有的session中互相传递使用,直到spark的应用终结,该咋办
- 这个时候我们只需要创建一个全局临时视图即可
全局临时视图
- 全局临时视图存在于系统数据库的
global_temp
中 - 全局临时视图的生命周期随spark程序的运行消失
- 来吧让我们用代码说话,代码案例:
try {
//创建全局临时视图
dataset.createGlobalTempView("user");
//全局临时视图绑定到系统保存的数据库“global_temp”
Dataset<Row> globalUser = sparkSession.sql("SELECT * FROM global_temp.user");
sparkSession.newSession().sql("SELECT * FROM global_temp.user");
} catch (AnalysisException e) {
e.printStackTrace();
}
- 代码还是很简单的
- 首先创建我们的全局临时视图,使用
createGlobalTempView
函数创建(在上一章节中创建临时视图使用的函数是createOrReplaceTempView
) - 其次我们说了,我们的全局临时视图绑定到我们的系统库 global_temp中,所以在查询的时候需要先指定我们的系统库(系统库无需关注,系统自带的)
- 最后呢,我们说过,全局临时变量是跨会话的,所以你可以在新会话中执行我们的SQL语句
创建DataSet
- DataSet和RDD比较类似,不同的地方就是序列化的方式
- RDD序列化是使用Java的serialization或者kryo实现序列化和反序列化的
- DataSet是使用的encoder来实现对象的序列化和在网络中的传输
- encoder有个动态的特性,Spark在执行比如sorting之类的操作时无需再把字节反序列化成对象
代码示例:
SparkSession sparkSession = SparkSession.builder().master("local")
.appName("Java Spark SQL")
.getOrCreate();
Person person = new Person("spark",10);
Encoder<Person> encoder = Encoders.bean(Person.class);
Dataset<Person> dataset = sparkSession.createDataset(Collections.singletonList(person),encoder);
dataset.show();
//最终输出 {name:spark;age:10}
/*常见类型的编码器*/
Encoder<Integer> integerEncoder = Encoders.INT();
Dataset<Integer> integerDataset = sparkSession.createDataset(Arrays.asList(1,2),integerEncoder);
Dataset<Integer> result = integerDataset.map(new MapFunction<Integer, Integer>() {
@Override
public Integer call(Integer value) {
return value+1;
}
},integerEncoder);
result.collect();
//最终输出 [2,3]
/*通过提供一个类,可以将数据流转换为数据集。基于名称的映射*/
String url = "/usr/local/text.json";
Dataset<Person> personDataset = sparkSession.read().json(url).as(encoder);
personDataset.show();
//最终输出 name:... age:,,,,
- 上面这个案例如何理解?
- 灵魂画手上线:
* - 这样就很好理解了,下面两个案例同理,只是数据类型为基础类型
这章的最后在这里总结一下 RDD和dataframe,DataSet的区别
-
RDD
- 弹性分布式数据集.是Spark对数据进行的一种抽象,可以理解为Spark对数据的一种组织方式.更简单些说.RDD就是一种数据结构.里面包含了数据和操作数据的方法
- 关键字:
- 弹性,分布式,数据集
-
DataFrame
- 理解了RDD.DataFrame就容易理解些
- RDD是一个数据集,DataFrame在RDD的基础上增加了Schema(描述数据的信息,可以认为是元数据,DataFrame曾经就叫做schemaRDD)
- 做个对比,如果左边的数据是RDD,那么右边的就是dataframe
- DataFrame比RDD多了一个表头信息(Schema),像一张表,DataFrame还配套了新的操作数据的方法,DataFrameAPI 比如df.select()和SQL(select id, name from xx_table where …))等等
- 正因为有了这层抽象,我们开发才能很爽啊,处理数据就变得很简单了
- 不仅如此.通过DataFrame API或SQL处理数据.会自动经过Spark的优化器(Catalyst)的优化.即使你写的程序或SQL不高效,也可以运行的很快
- 注意:DataFrame是用来处理结构化数据的
-
DataSet
- 对于RDD而言,DataSet做了强类型支持,在RDD的每一行都做了数据类型约束
- RDD转换DataFrame后不可逆,但RDD转换Dataset是可逆的
- 下面这就是DataSet的数据
这章就先到这里啦,这章我们知道了创建DataSet的方式还有RDD和dataframe,dataset的区别
下一章节写RDD和DataSet的转换操作吧