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对象,它内置 ...
随机推荐
- js实现截取字符串后几位
var strs ="wdsdabcdefages" strs.substring(obj.filename.lastIndexOf("a")+1,strs.l ...
- 百度网盘Mac版如何分享链接?创建百度网盘 for Mac分享链接的方法
想把自己百度网盘里的数据分享给朋友,该怎么操作呢?有很多朋友使用百度网盘,可以很轻松的自己的文件上传到网盘上,并可跨终端随时随地查看和分享.下面Mac down小编就给大家介绍一下创建百度网盘 for ...
- H5调用百度地图导航
template <div class="map"> <div class="content_flex"><img src=&qu ...
- Q: 微信小程序登录
这里使用的mpvue 第一步组件DOM部分 /pages/index <button class="app_btn" open-type="getUserInfo& ...
- SQL SERVER中[dbo]的解释
1.作用: (1)DBO是每个数据库的默认用户,具有所有者权限,即DbOwner:通过用DBO作为所有者来定义对象,能够使数据库中的任何用户引用而不必提供所有者名称.(2)至于为什么要使用所有者进行限 ...
- 字符串匹配dp+bitset,滚动数组优化——hdu5745(经典)
bitset的经典优化,即把可行性01数组的转移代价降低 bitset的适用情况,当内层状态只和外层状态的上一个状态相关,并且内层状态的相关距离是一个固定的数,可用bitset,换言之,能用滚动数组是 ...
- 解决php-fpm占用cpu memory过高,开启php-fpm request_slowlog_timeout
项目刚从win下挪到linux下,发现cpu过高,内存也占用较多,以下是我解决问题的过程: 首先更改php-fpm配置 vim /usr/local/php/etc/php-fpm.conf 找到 r ...
- P1831 杠杆数
P1831 杠杆数 题目描述 如果把一个数的某一位当成支点,且左边的数字到这个点的力矩和等于右边的数字到这个点的力矩和,那么这个数就可以被叫成杠杆数. 比如4139就是杠杆数,把3当成支点,我们有这样 ...
- 微信-小程序-开发文档-服务端-接口调用凭证:auth.getAccessToken
ylbtech-微信-小程序-开发文档-服务端-接口调用凭证:auth.getAccessToken 1.返回顶部 1. auth.getAccessToken 本接口应在服务器端调用,详细说明参见服 ...
- 6. 第一个jmeter脚本开发-测试百度首页
需求:可以承受5个用户同时访问百度解题思路:我们可以从这短短的一句话中提取3个点:同时.5个并发.百度服务器解题方法:方法一:录制请求录制方法会在下一篇进行讲解,本篇不做过多介绍. 方法二:自定义添加 ...