Learning Spark 学习笔记 第三章 RDDs编程


概述:

RDD(resilient distributed dataset,弹性分布式数据集),是一个抽象概念,是可分布式存储和处理的数据的集合。spark中可进行RDD的创建;转化已存在的RDD为一个新的RDD;在RDD上进行分布式处理,并行计算得到结果(value)。


RDD基础:

RDD可分成多个分区,每个分区分布在集群节点上。RDDs可包含python,java,scala对象类型(包含自定义类对象)。有两种创建方式:从外部数据集装载;已有driver program种的一个数据list或者set对象集合。例如之前一篇中lines = sc.textFile("README.md"),用textFile创建(每行作为一个item的RDD)

RDD创建之后有两种操作可进行:transformations(转换,从一个RDD经过特定处理到另一个RDD);  actions(在RDD上处理得到一个确定的结果)。

transformations:例如 val pythonLines = lines.filter(line => line.contains("Python"))//从每行作为一个item的RDD中过滤出包含单词Python的行构成的RDD。

actions:在RDD上处理得到一个确定的结果,结果可返回给driver program或者存到外部存储系统(例如HDFS)。例如:pythonLines.first()就是在RDD pythonLines上进行一个action得到结果(RDD的第一个item)。

RDD架构之所以好在:惰性计算。在action阶段才对数据集进行计算。转换阶段并不对数据进行加载存储(相反MapReduce会对每次结果进行存储到disk中),因此较高效。例如lines = sc.textFile(...)后并不进行对每一行进行加载存储,若进行加载存储之后filter阶段还会再一次加载存储。而action first()只需对最终的转换RDD处理得到第一行就可以,无需读取整个文件。

在第一次对RDD进行action之后,spark会存储RDD的内容到内存中(也是分布式存储到集群上)而不是disk中。RDD.persist()操作会把数据持久化到disk中,便于多次对RDD进行action(我理解为:RDD1->RDD2->RDD3,在RDD3上进行action时才进行RDD1到RDD3的转换并做相应action的计算,此时如果再次action,那么会重新从RDD1来一次。如果RDD2进行持久化后,从RDD2开始就可以了),例如: pythonLines.persist  pythonLines.count()  pythonLines.first()。若不会重复使用RDD则无需进行持久化而浪费存储空间。

因此,每个spark程序或shell会话如下流程:

1.从外部数据中创建RDDs

2.对RDDs进行转换成新的RDDs,例如filter()操作

3.若要对RDDs进行重复使用,则需persist()持久化

4.actions例如count(),first(),启动并行的计算,spark会对计算任务进行优化和执行。

创建RDDs:

一:把一个已存在的集合传给SparkContext的parallelize()方法得到。例如 val lines = sc.parallelize(List("pandas", "i like pandas"))

二:从外部数据集装载。详细会在第五章讲,但是之前我们已经见识过一种文件中得到RDD的方式(每行作为一个item,数据的inputformat决定):val lines = sc.textFile("/path/to/README.md")

RDD的操作:

RDD支持transformations(RDDs转为新的RDDs,例如map(),filter()操作)和actions(在集群上启动一个分布式计算得到一个结果返回给driber program或存储起来,例如count(),first()操作)。区分操作是transformations还是actions:返回类型为RDDs为转换,为其他数据类型是actions。

transformations:例如一个logfile inputRDD,我们通过filter进行过滤转换出含有error的errorsRDD,之后我们还可以filter出含有warning的warningsRDD,新的RDD都会存于内存中,同样我们可以依赖于errorsRDD和warningsRDD进行转换操作(badLinesRDD = errorsRDD.union(warningsRDD)),如下图所示,spark会记录此过程:



因此若某个环节的RDD持久化的数据损坏了,还可以进行修复,这也是spark的容错机制。

actions:例如如下

println("Input had " + badLinesRDD.count() + " concerning lines")
println("Here are 10 examples:")
badLinesRDD.take(10).foreach(println)
//take收集十个item到driver program(返回结果到driver program)

driver program通常部署在name node,collect() action可以收集整个RDD到driver program,若你的RDD小数据量,且你希望在本地进行处理可进行collect,若大数据不可,你可以通过saveAsTextFile()或saveAsSequenceFile()或者其他formats的存储到系统(HDFS或者S3中)。需要注意的是,每次action都会使RDD重头开始计算,因此可以通过持久化中间结果来避免效率低下。

惰性计算:每次RDD转换并不会立即计算,在遇到action时才计算。RDD可想象成记录怎么转换数据的操作,而不是数据集合,这样会把转换操作集中,减少数据传递。

Passing Functions to Spark:此小节看不懂啥意思啊!望有人看到可以指导下

常用的一些transformations和actions:

最常用的transformations为map和filter:


map可理解为MapReduce中的map阶段,map的输入和输出类型可不同,inputRDD为string,map出的RDD可为double等。filter就是过滤出一个子集RDD。flatMap()返回values的迭代器,功能可用来把string分为words:

val lines = sc.parallelize(List("hello world", "hi"))
val words = lines.flatMap(line => line.split(" "))
words.first()  // returns "hello"

map和flatmap区别如下图所示:

RDD1中“”中为一个item,操作tokenize是把每个item list化,map的结果是RDD1的一个item编程mappedRDD中一个item(是一个list[“”,“”]),flagmap则把RDD1的每个item得到的list再进行flattening,每个单词为一个item。

RDD还支持一些数学集合操作:


distinct进行去重,union是并集,intersection是交集,subtract差集。


cartesian(other)是求两个RDD item的所有组合。

常用的actions:

reduce():val sum = rdd.reduce((x, y) => x + y),类似于MapReduce的reduce概念。

若RDD {1,2,3,3},如下action:




图中很容易理解,不一一解释了。


Converting Between RDD Types 小节暂没看。


持久化:

spark有如下持久化选择:

使用如下(在action之前进行持久化,unpersist()从cache移除):

val result = input.map(x => x * x)
result.persist(StorageLevel.DISK_ONLY)
println(result.count())
println(result.collect().mkString(","))

若你试图持久化很多数据,使用LRU策略进行内存管理。

总结:

对RDD有了又一步深入的了解,但是还不够透彻,有的地方可能自己理解的也有错误,接受指正。看完这本书之后再去看别的加以深入。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

hjbbjh0521

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值