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对象,它内置 ...
随机推荐
- vue 中使用 lazyload 插件 数据更图片不更新 的原因 及解决方案
在使用lazyload插件的img标签上,加上:key标识即可
- 通过statCounter计算给定的RDD[Double]的统计信息的方法
需求1:给定一个RDD[Double],进行计算,该RDD的统计信息(count,mean,stdev,max,min) 代码: def main(args: Array[String]): Unit ...
- 51. TreeSet
集合分类:-------------------| Collection 单列集合的根接口 ---------------| List 如果实现了List接口的集合类,具备的特点是:有序,可重复- ...
- 本地仓库_remote.repositories(拒绝访问)
问题描述: 通过阿里云配置本地的 Maven 仓库,使用 Maven 命令在进行打包.编译等一系列操作时候,总是出现提示某个 Jar 文件 ---> 『.....\ _remote.reposi ...
- Kotlin Download
{ https://github.com/JetBrains/kotlin/releases/tag/v1.3.50 }
- 高危预警| SQL数据库成主要攻击对象,或引发新一轮大规模勒索
近日,阿里云安全团队发现,目前互联网上的服务器,SQL数据库仍然有不少处于直接暴露在公网的状态,且数量有上升趋势.黑客可以利用数据库存在的漏洞或弱口令直接获取数据,并植入勒索和挖矿病毒寻求牟利.阿里云 ...
- 欧拉函数+反演——2019hdu多校6588
\[ 求\sum_{i=1}^{n}(\sqrt[3]i,i)\\ 首先转化一下这个式子,考虑对于i\in[j^3,(j+1)^3-1],\sqrt[3]i=j\\ 所以可以枚举所有j,然后对i\in ...
- csp-s模拟测试95
csp-s模拟测试95 去世场祭. $T1$:这不裸的除法分块吗. $T2$:这不裸的数据结构优化$Dp$吗. $T3$:这不裸的我什么都不会搜索骗$30$分吗. 几分钟后. 这除法分块太劲了..(你 ...
- (转)简单的RPC java实现 .
转:http://blog.csdn.net/jackliang55/article/details/7580563 我也承认,RPC的名声大噪之时是在2003年,那一个“冲击波”病毒(Blaster ...
- Linux下同一目录内文件和目录为什么不能同名?
问题描述: 如果事先有叫‘A’的文件夹存在,则不允许建立叫‘A’的文件: 同理若先有叫‘b’的文件存在,一样不允许建立叫‘b’的文件夹. 原因很简单,因为Linux下一切都是文件,一个目录归根到底还是 ...
