RDD:弹性分布式数据集(ResilientDistributed Dataset),是Spark对数据的核心抽象。RDD其实是分布式的元素集合。当Spark对数据操作和转换时,会自动将RDD中的数据分发到集群,并将操作并行化执行。
Spark中的RDD是一个不可变的分布式对象集合。每个RDD都倍分为多个分区,这些分区运行在集群中的不同节点。RDD可以包含Python、Java、Scala中任意类型的对象,甚至可以包含用户自定义对象,本文主要通过Java实现相关示例。
Spark程序或shell会话工作流程
1. 从外部数据创建出输入RDD;
2. 使用诸如filter()等这样的转化操作对RDD进行转化,以定义新的RDD;
3. 告诉Spark对需要被重用的中间结果RDD执行persist()操作;
4. 使用诸如first()等这样的行动操作来触发一次并行计算,Spark会对计算进行优化后再执行。
Spark提供了两种创建RDD方式:
1. 读取外部数据集,如文件,hive数据库等;
2. 在驱动器程序中对一个集合进行并行化,如list,set等。
方法1是常用方法,其从外部存储中读取数据来创建RDD,如读取文件
方法2其实使用较少,毕竟它需要把整个数据集先放在一台机器的内存中。实现也简单,就是把程序中一个已有集合传给SparkContext的parallelize()方法。二.RDD操作
(1) 转化操作,RDD的转化操作是返回一个新的RDD的操作,比如map()和filter。
(2) 行动操作,RDD的行动操作则是向驱动器程序返回结果或把结果写入外部系统的操作,会触发实际的计算,比如count()和first()。
惰性求值:RDD的转化操作是惰性求值的,即在被调用行动操作之前Spark不会开始计算,相反,Spark会在内部记录下索要求执行的操作的相关信息。例如,当我们调用jsc.textFile()时,数据并没有读取进来,而是在必要时才会读取。Spark使用惰性求值,就可以把一些操作合并到一起来减少计算数据的步骤。
函数名 |
目的 |
示例 |
结果 |
map() |
将函数应用于RDD的每一元素, |
rdd.map(x=>x+1) |
{2,3,4,4} |
flatMap() |
将函数应用于RDD的每一元素, |
rdd.flatMap(x=>x.to(3)) |
{1,2,3,2,3,3,3} |
filter() |
返回一个由通过传给filter()的函数 |
rdd.filter(x=>x!=1) |
{2,3,3} |
distinct() |
去重 |
rdd.distinct() |
{1,2,3) |
sample(withReplacement, |
对RDD采用,以及是否替换 |
rdd.sample(false,0.5) |
非确定的 |
对一个数据为{1,2,3,3}的RDD进行基本的RDD转化操作
函数名 |
目的 |
示例 |
结果 |
union() |
生成一个包含两个RDD 中所有元素的RDD |
rdd.union(other) |
{1, 2, 3, 3, 4, 5} |
intersection() |
求两个RDD 共同的元素的RDD |
rdd.intersection(other) |
{3} |
subtract() |
移除一个RDD 中的内容(例如移除训练数据) |
rdd.subtract(other) |
{1, 2} |
cartesian() |
与另一个RDD 的笛卡儿积 |
rdd.cartesian(other) |
{(1, 3), (1, 4), ...(3, 5)} |
对数据分别为{1, 2,3}和{3, 4, 5}的RDD进行针对两个RDD的转化操作
函数名 |
目的 |
示例 |
结果 |
collect() |
返回RDD 中的所有元素 |
rdd.collect() |
{1, 2, 3, 3} |
count() |
RDD 中的元素个数 |
rdd.count() |
4 |
countByValue() |
各元素在RDD 中出现的次数 |
rdd.countByValue() |
{(1, 1),(2, 1),(3, 2)} |
take(num) |
从RDD 中返回num 个元素 |
rdd.take(2) |
{1, 2} |
top(num) |
从RDD 中返回最前面的num个元素 |
rdd.top(2) |
{3, 3} |
takeOrdered(num) |
从RDD 中按照提供的顺序返回最前面的num 个元素 |
rdd.takeOrdered(2)(myOrdering) |
{3, 3} |
takeSample(withReplacement, |
从RDD 中返回任意一些元素 |
rdd.takeSample(false, 1) |
非确定的 |
reduce(func) |
并行整合RDD 中所有数据(例如sum) |
rdd.reduce((x, y) => x + y) |
9 |
fold(zero)(func) |
和reduce() 一样, 但是需要提供初始值 注意:不重复元素加初始值,重复元素只加一个 |
rdd.fold(0)((x, y) => x + y) |
9 |
aggregate(zeroValue) |
和reduce() 相似, 但是通常返回不同类型的函数 注意:不重复元素加初始值,重复元素只加一个 |
rdd.aggregate((0, 0))((x, y) => |
(9,4) |
foreach(func) 对RDD |
中的每个元素使用给定的函数 |
rdd.foreach(func) |
无 |
对一个数据为{1, 2,3, 3}的RDD进行基本的RDD行动操作
在Java中,函数需要作为实现了Spark的org.apache,spark.api.java.function包中的任一函数接口的对象传递。
函数名 |
实现的方法 |
用途 |
Function |
R call(T) |
接收一个输入值并返回一个输出值,用于类似map() 和filter() 等操作中 |
Function2 |
R call(T1, T2) |
接收两个输入值并返回一个输出值,用于类似aggregate()和fold() 等操作中 |
FlatMapFunction |
Iterable |
接收一个输入值并返回任意个输出,用于类似flatMap()这样的操作中 |
标准Java函数接口
函数名 |
等价函数 |
用途 |
DoubleFlatMapFunction |
Function |
用于flatMapToDouble,以生成DoubleRDD |
DoubleFunction |
Function |
用于mapToDouble,以生成DoubleRDD |
PairFlatMapFunction |
Function |
用于flatMapToPair,以生成PairRDD |
PairFunction |
Function |
用于mapToPair, 以生成PairRDD |
Java中针对专门类型的函数接口
本节将通过示例的方式验证第二节中相关的转化操作和行动操作。
代码地址:http://download.csdn.net/detail/a123demi/9837375
参考文献:
王道远 《Spark 快速大数据分析》