Spark 读写数据、抽象转换 拾遗
读
package com.test.spark
import org.apache.spark.sql.{Dataset, Row, SaveMode, SparkSession}
/**
* @author Administrator
* 2019/7/22-17:09
*
*/
object TestReadData {
val spark = SparkSession
.builder()
.appName("TestCreateDataset")
.config("spark.some.config.option", "some-value")
.master("local")
.enableHiveSupport()
.getOrCreate()
def main(args: Array[String]): Unit = {
testRead
}
def testRead(): Unit = {
// parquet 如果有损坏啥的容易莫名的错误
val parquet: Dataset[Row] = spark.read.parquet("D:\\DATA-LG\\PUBLIC\\TYGQ\\INF\\PersonInfoCommon.parquet")
parquet.show()
// Spark SQL 的通用输入模式
val commonRead: Dataset[Row] = spark.read.format("json").load("D:\\DATA-LG\\PUBLIC\\TYGQ\\INF\\testJson")
commonRead.show()
// Spark SQL 的通用输出模式
commonRead.write.format("parquet").mode(SaveMode.Append).save("D:\\DATA-LG\\PUBLIC\\TYGQ\\INF\\PersonInfoCommon.parquet")
// Spark SQL 的专业输入模式
val professionalRead: Dataset[Row] = spark.read.json("D:\\DATA-LG\\PUBLIC\\TYGQ\\INF\\testJson")
professionalRead.show()
// Spark SQL 的专业输出模式
professionalRead.write.mode(SaveMode.Append).parquet("D:\\DATA-LG\\PUBLIC\\TYGQ\\INF\\PersonInfoProfessional.parquet")
val readParquet: Dataset[Row] = spark.sql("select * from parquet.`D:\\DATA-LG\\PUBLIC\\TYGQ\\INF\\PersonInfoCommon.parquet`")
readParquet.show()
}
}
//输出:
+---+---------------+---------+
|age| ip| name|
+---+---------------+---------+
| 24| 192.168.0.8| lillcol|
|100| 192.168.255.1| adson|
| 39| 192.143.255.1| wuli|
| 20| 192.168.255.1| gu|
| 15| 243.168.255.9| ason|
| 1| 108.168.255.1| tianba|
| 25|222.168.255.110|clearlove|
| 30|222.168.255.110|clearlove|
+---+---------------+---------+
+---+---------------+---------+
|age| ip| name|
+---+---------------+---------+
| 24| 192.168.0.8| lillcol|
|100| 192.168.255.1| adson|
| 39| 192.143.255.1| wuli|
| 20| 192.168.255.1| gu|
| 15| 243.168.255.9| ason|
| 1| 108.168.255.1| tianba|
| 25|222.168.255.110|clearlove|
| 30|222.168.255.110|clearlove|
+---+---------------+---------+
+---+---------------+---------+
|age| ip| name|
+---+---------------+---------+
| 24| 192.168.0.8| lillcol|
|100| 192.168.255.1| adson|
| 39| 192.143.255.1| wuli|
| 20| 192.168.255.1| gu|
| 15| 243.168.255.9| ason|
| 1| 108.168.255.1| tianba|
| 25|222.168.255.110|clearlove|
| 30|222.168.255.110|clearlove|
+---+---------------+---------+
+---+---------------+---------+
|age| ip| name|
+---+---------------+---------+
| 24| 192.168.0.8| lillcol|
|100| 192.168.255.1| adson|
| 39| 192.143.255.1| wuli|
| 20| 192.168.255.1| gu|
| 15| 243.168.255.9| ason|
| 1| 108.168.255.1| tianba|
| 25|222.168.255.110|clearlove|
| 30|222.168.255.110|clearlove|
| 24| 192.168.0.8| lillcol|
|100| 192.168.255.1| adson|
| 39| 192.143.255.1| wuli|
| 20| 192.168.255.1| gu|
| 15| 243.168.255.9| ason|
| 1| 108.168.255.1| tianba|
| 25|222.168.255.110|clearlove|
| 30|222.168.255.110|clearlove|
+---+---------------+---------+
保存
文件保存选项
模式 | 注释 |
---|---|
Append | DataFrame的内容将被追加到现有数据中。 |
Overwrite | 现有数据将被数据Daframe的内容覆盖。 |
ErrorIfExists | 如果数据已经存在,报错。 |
Ignore | 如果数据已经存在,不执行任何操作 |
注:这些保存模式不使用任何锁定,不是原子操作。
如果使用 Overwrite 同时该路径(path)又是数据源路径,要先对数据进行持久化操作,
否则会在读取path之前将该数据删除掉,导致后续lazy 读取数据的时候报文件不存在的错误。
类型之间的转换
之前关于Spark 三中抽象之间的转换老是有些纠结
现在对它们之间的转换做个总结
在 SparkSQL 中 Spark 为我们提供了两个新的抽象,分别是 DataFrame 和 DataSet。
他们和 RDD 有什啥关系呢?
首先从版本的产生上来看:RDD(Spark1.0) —> DataFrame(Spark1.3) —> DataSet(Spark1.6)
如果同样的数据都给到这三个数据结构,他们分别计算之后,都会给出相同的结果。
不同是的他们的执行效率和执行方式。
在后期的 Spark 版本中,DataSet 会逐步取代 RDD 和 DataFrame 成为唯一的 API 接口。
所以后续开发 我更多的面向DataSet进行开发了。
RDD
- RDD 弹性分布式数据集,Spark 计算的基石,为用户屏蔽了底层对数据的复杂抽象和处理,为用户提供了一组方便的数据转换与求值方法。
- RDD 是一个懒执行的不可变的可以支持 Lambda 表达式的并行数据集合。
- RDD 的最大好处就是简单,API 的人性化程度很高。
- RDD 的劣势是性能限制,它是一个 JVM 驻内存对象,这也就决定了存在 GC 的限制和数据增加时 Java 序列化成本的升高。
DataFrame
- 与 RDD 类似,DataFrame 也是一个分布式数据容器。
- 然而 DataFrame 更像传统数据库的二维表格,除了数据以外,还记录数据的结构信息,即 schema。
- 与 Hive 类似,DataFrame 也支持嵌套数据类型(struct、array 和 map)。
- 从 API 易用性的角度上看,DataFrame API 提供的是一套高层的关系操作,比函数式的 RDD API 要更加友好,门槛更低。
- 由于与 R 和 Pandas 的 DataFrame 类似,Spark DataFrame 很好地继承了传统单机数据分析的开发体验。
Q: DataFrame性能上比 RDD 要高的原因:
A:主要有两个原因
- 定制化内存管理
数据以二进制的方式存在于非堆内存,节省了大量空间之外,还摆脱了 GC 的限制。
- 优化的执行计划
查询计划通过 Spark catalyst optimiser 进行优化。
DataSet
- 是 DataFrame API 的一个扩展,是 Spark 最新的数据抽象。
- 用户友好的 API 风格,既具有类型安全检查也具有 DataFrame 的查询优化特性。
- DataSet 支持编解码器,当需要访问非堆上的数据时可以避免反序列化整个对象,提高了效率。
- 样例类被用来在 DataSet 中定义数据的结构信息,样例类中每个属性的名称直接映射到 DataSet 中的字段名称。
- DataFrame 是 DataSet 的特列,type DataFrame = Dataset[Row] ,所以可以通过 as 方法将 DataFrame 转换为 DataSet。Row 是一个类型,跟 Car、Person 这些的类型一样,所有的表结构信息都用 Row 来表示。
- DataSet 是强类型的。比如可以有 Dataset[Car],Dataset[Person],
DataFrame 只是知道字段,但是不知道字段的类型,所以在执行这些操作的时候是没办法在编译的时候检查是否类型失败的,比如你可以对一个 String 进行减法操作,在执行的时候才报错,
而 DataSet 不仅仅知道字段,而且知道字段类型,所以有更严格的错误检查。
就跟 JSON 对象和类对象之间的类比。
三者之间的转换
case class Person(name: String, age: Long) extends Serializable //case class的定义要在引用case class函数的外面。
import spark.implicits._
//类型之间的转换:注意输出类型
def rddSetFrame() = {
// 在使用一些特殊的操作时,一定要加上 import spark.implicits._ 不然 toDF、toDS 无法使用。
val rdd: RDD[String] = spark.sparkContext.textFile("D:\\DATA-LG\\PUBLIC\\TYGQ\\INF\\testFile")
val ds: Dataset[Row] = spark.read.json("D:\\DATA-LG\\PUBLIC\\TYGQ\\INF\\testJson")
val df: DataFrame = rdd.map(_.split(",")).map(strArr => (strArr(0).trim(), strArr(1).trim().toInt)).toDF("nama", "age")
// rdd->df
//一般用元组把一行的数据写在一起,然后在 toDF 中指定字段名。
val rddTDf: DataFrame = rdd.map(_.split(",")).map(strArr => (strArr(0).trim(), strArr(1).trim().toInt)).toDF("nama", "age")
// df -> rdd
val dfTRdd: RDD[Row] = df.rdd;
// rdd -> ds
//定义每一行的类型 case class 时,已经给出了字段名和类型,后面只要往 case class 里面添加值即可。
val rddTDs: Dataset[Person] = rdd.map(_.split(",")).map(strArr => Person(strArr(0).trim(), strArr(1).trim().toInt)).toDS()
// ds -> rdd
val dsTRdd: RDD[Person] = rddTDs.rdd
// df->ds
//这种方法就是在给出每一列的类型后,使用 as 方法,转成 DataSet,这在数据类型是 DataFrame 又需要针对各个字段处理时极为方便。
val dfTDs: Dataset[Person] = df.as[Person]
// ds->df
// 只是把 case class 封装成 Row。
val dsTDf: DataFrame = ds.toDF
}
Spark 读写数据、抽象转换 拾遗的更多相关文章
- Spark SQL数据加载和保存实战
一:前置知识详解: Spark SQL重要是操作DataFrame,DataFrame本身提供了save和load的操作, Load:可以创建DataFrame, Save:把DataFrame中的数 ...
- Spark大数据针对性问题。
1.海量日志数据,提取出某日访问百度次数最多的那个IP. 解决方案:首先是将这一天,并且是访问百度的日志中的IP取出来,逐个写入到一个大文件中.注意到IP是32位的,最多有个2^32个IP.同样可以采 ...
- 使用Spark读写CSV格式文件(转)
原文链接:使用Spark读写CSV格式文件 CSV格式的文件也称为逗号分隔值(Comma-Separated Values,CSV,有时也称为字符分隔值,因为分隔字符也可以不是逗号.在本文中的CSV格 ...
- Spark SQL数据载入和保存实战
一:前置知识具体解释: Spark SQL重要是操作DataFrame,DataFrame本身提供了save和load的操作. Load:能够创建DataFrame. Save:把DataFrame中 ...
- Spark 读写hive 表
spark 读写hive表主要是通过sparkssSession 读表的时候,很简单,直接像写sql一样sparkSession.sql("select * from xx") 就 ...
- Spark读写HBase
Spark读写HBase示例 1.HBase shell查看表结构 hbase(main)::> desc 'SDAS_Person' Table SDAS_Person is ENABLED ...
- 学习Hadoop+Spark大数据巨量分析与机器学习整合开发-windows利用虚拟机实现模拟多节点集群构建
记录学习<Hadoop+Spark大数据巨量分析与机器学习整合开发>这本书. 第五章 Hadoop Multi Node Cluster windows利用虚拟机实现模拟多节点集群构建 5 ...
- opencv IplImage各参数详细介绍以及如何从一个JPEG图像数据指针转换得到IplImage
这篇文章里介绍得最清楚了.http://blog.chinaunix.net/uid-22682903-id-1771421.html 关于颜色空间 RGB颜色空间已经非常熟悉了.HSV颜色空间需要 ...
- Python 学习 第17篇:从SQL Server数据库读写数据
在Python语言中,从SQL Server数据库读写数据,通常情况下,都是使用sqlalchemy 包和 pymssql 包的组合,这是因为大多数数据处理程序都需要用到DataFrame对象,它内置 ...
随机推荐
- 使用sqlyog工具同步两个相同结构的数据库之间的数据
compare two database data 因为工作上遇到 同一个项目被部署到不同服务器上,原项目(后统称"源")在运行中,后部署的项目(后统称"目标" ...
- java zxing 生成条形码和二维吗
依赖 <dependency> <groupId>com.google.zxing</groupId> <artifactId>core</art ...
- Vue开发实战
递归组件 关键是组件在模板内能调用自身,关键是name属性 首先我们先定义数据格式 list: [ { title: '标题1' }, { title: '标题2', children: [ { ti ...
- 利用reduce方法,对数组中的json对象去重
数组中的json对象去重 var arr = [{ "name": "ZYTX", "age": "Y13xG_4wQnOWK1Q ...
- Exception一自定义异常
异常体系的根类是:Throwable Throwable: Error: 重大的问题,我们处理不了.也不需要编写代码处理.比如说内存溢出. Exception: 一般性的错误,是需要我们对编写 ...
- JavaWeb学习篇之----Servlet过滤器Filter和监听器
首先来看一下Servlet的过滤器内容: 一.Servlet过滤器的概念: ************************************************************** ...
- bzoj1040题解
[题意分析] 给你一个带权基环树森林,求它的点集的无邻点子集的最大权值和. [解题思路] 对于树的部分,做一遍拓扑排序+递推即可(f[i][j]表示第i个节点选取状态为j(0/1)可以得到的最大权值和 ...
- NX二次开发-UFUN重命名图纸页UF_DRAW_rename_drawing
#include <uf.h> #include <uf_draw.h> #include <uf_drf.h> #include <uf_obj.h> ...
- hdu多校第九场 1002 (hdu6681) Rikka with Cake 树状数组维护区间和/离散化
题意: 在一块长方形蛋糕上切若干刀,每一刀都是从长方形某条边开始,垂直于这条边,但不切到对边,求把长方形切成了多少块. 题解: 块数=交点数+1 因为对于每个交点,唯一且不重复地对应着一块蛋糕. 就是 ...
- Matlab求三重积分
Matlab求三重积分 求 \(\int_0^1 \int_0^1 \int_0^1 sin(\pi x_1 x_2 x_3) dx_1 dx_2 dx_3\) 代码是: triplequad(@(x ...