1.RDD基本概念
Spark中的RDD是一个不可变的分布式对象集合,有五大特性:
①有一个分片列表。就是能被切分,和hadoop一样的,能够切分的数据才能并行计算。
②有一个函数计算每一个分片,这里指的是下面会提到的compute函数。
③对其他的RDD的依赖列表,依赖还具体分为宽依赖和窄依赖,但并不是所有的RDD都有依赖。
④可选:key-value型的RDD是根据哈希来分区的,类似于mapreduce当中的Paritioner接口,控制key分到哪个reduce。
⑤可选:每一个分片的优先计算位置(preferred locations),比如HDFS的block的所在位置应该是优先计算的位置。(存储的是一个表,可以将处理的分区“本地化”)
2.RDD创建方式
①(常用)读取外部数据集:
val rdd1=sc.textFile("/path/to/readme.md")
②在驱动程序中对另一个集合并行化:
val rdd2=sc.parallelize(List("apple","banana","orange"))
[注:一般在开发原型或测试时才使用]
3.Spark程序或shell会话工作流程
①从外部数据创建出输入RDD;
②使用诸如filter()等这样的转化操作对RDD进行转化,以定义新的RDD;
③告诉Spark对需要被重用的中间结果RDD执行persist()操作;
④ 使用诸如first()等这样的行动操作来触发一次并行计算,Spark会对计算进行优化后再执行。
4.RDD操作
(1)获取RDD
①从共享的文件系统获取(如:HDFS)
②通过已存在的RDD转换
③将已存在scala集合(只要是Seq对象)并行化,通过调用SparkContext的parallelize方法实现
④改变现有的RDD的持久性;RDD是懒散的,短暂的.RDD的固话:cache缓存至内存;save保存到分布式文件系统
(2)转化操作(返回一个新的RDD)
函数名 | 目的 | 示例 rdd{1,2,3,3} rdd2{1,2,3} other{3,4,5} | 结果 |
---|---|---|---|
map(func) | 返回一个新的分布式数据集, 由每个原元素经过func函数转换后组成 | rdd.map(x=>x+1) | {2,3,4,4} |
filter(func) | 返回一个新的数据集, 由经过func函数后返回值为true的原元素组成 | rdd.filter(x=>x!=1) | {2,3,3} |
flatMap(func) | 类似于map,但是每一个输入元素,会被映射为0到多个输出元素 (因此,func函数的返回值是一个Seq,而不是单一元素) | rdd.flatMap(x=>x.to(3)) | {1,2,3,2,3,3,3} |
distinct() | 去重 | rdd.distinct() | {1,2,3} |
union(other) | 返回一个新的数据集,由原数据集和参数联合而成 | rdd2.union(other) | {1,2,3,3,4,5} |
intersection(other) | 求两个RDD共同的元素的RDD | rdd.intersection(other) | {3} |
subtract(other) | 移除一个RDD中的内容(例如移除训练数据) | rdd.subtract(other) | {1, 2} |
cartesian(other) | 笛卡尔积。但在数据集T和U上调用时,返回一个 (T,U)对的数据集,所有元素交互进行笛卡尔积。 | rdd.cartesian(other) | {(1, 3), (1, 4), ...(3, 5)} |
groupWith(otherDataset, [numTasks]) | 在类型为(K,V)和(K,W)类型的数据集上调用,返回一个数据集, 组成元素为(K, Seq[V], Seq[W]) Tuples。这个操作在其它框架,称为CoGroup | ||
reduceByKey(func, [numTasks]) | 对于(k,v)对的数据集,则是合并key相同的键值对 |
(3)行动操作(向驱动器程序返回结果或把结果写入外部系统的操作)
函数名 | 目的 | 示例 rdd{1,2,3,3} | 结果 |
collect() | 返回RDD中所有元素 | rdd.collect() | {1,2,3,4} |
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)(ordering) | 从RDD中按照提供的顺序返回最前面的num个元素 | rdd.takeOrdered(2)(myOrdering) | {3,3} |
reduce(func) | 并行整合RDD中所有数据(例如sum) | rdd.reduce((x,y)=>x+y) | 9 |
fold(zero)(func) | 和reduce()一样,但要提供初始值;注意:不重复元素加初始值,重复元素只加一个 | rdd.fold(0)((x,y)=>x+y) | |
saveAsTextFile(path) | 将数据集的元素,以textfile的形式,保存到本地文件系统,hdfs或者任何其 它hadoop支持的文件系统Spark将会调用每个元素的toString方法,并将它转换为文件中的一行文本 |
| |
saveAsSequenceFile(path) | 将数据集的元素,以sequencefile的格式保存到指定的目录下本地系统, hdfs或者任何其它hadoop支持的文件系统。RDD的元素必须由key-value 对组成,并都实现了Hadoop的Writable接口,或隐式可以转换为Writable |
|
5.Pair RDD
函数名 | 目的 | 示例rdd{(1,2),(3,4),(3,6)} other{(3,9)} | 结果 |
---|---|---|---|
reduceByKey(func) | 合并具有相同键的值 | rdd.reduceByKey((x, y) => x + y) | {(1,2), (3,10)} |
groupByKey() | 对具有相同键的值进行分组 | rdd.groupByKey() | {(1,[2]),(3, [4,6])} |
mapValues(func) | 对pair RDD 中的每个值应用一个函数而不改变键 | rdd.mapValues(x => x+1) | {(1,3), (3,5), (3,7)} |
flatMapValues(func) | 对pair RDD 中的每个值应用一个返回迭代器的函数,然后对返回的每个元素都生成一个对应原键的键值对记录通常用于符号化 | rdd.flatMapValues(x => (x to 5)) | {(1,2), (1,3), (1,4), (1,5), (3,4), (3,5)} |
keys() | 返回一个仅包含键的RDD | rdd.keys() | {1, 3,3} |
values() | 返回一个仅包含值的RDD | rdd.values() | {2, 4,6} |
sortByKey() | 返回一个根据键排序的RDD | rdd.sortByKey() | {(1,2), (3,4), (3,6)} |
subtractByKey | 删掉RDD 中键与other RDD 中的键 相同的元素 | rdd.subtractByKey(other) | {(1, 2)} |
join | 对两个RDD 进行内连接 | rdd.join(other) | {(3, (4, 9)), (3,(6, 9))} |
rightOuterJoin | 对两个RDD 进行连接操作, 确保第一个RDD 的键必须存在 (右外连接) | rdd.rightOuterJoin(other) | {(3,(Some(4),9)), 3,(Some(6),9))} |
leftOuterJoin | 对两个RDD 进行连接操作, 确保第二个RDD 的键必须存在 (左外连接) | rdd.leftOuterJoin(other) | {(1,(2,None)), (3,(4,Some(9))), (3,(6,Some(9)))} |
cogroup | 将两个RDD 中拥有相同键的 数据分组到一起 | rdd.cogroup(other) | {(1,([2],[])), (3,([4, 6],[9]))} |
countByKey() | 对每个键对应的元素分别计数 | rdd.countByKey() | {(1, 1), (3, 2)} |
collectAsMap() | 将结果以映射表的形式返回, 以便查询 | rdd.collectAsMap() | Map{(1, 2), (3,4), (3, 6)} |
lookup(key) | 返回给定键对应的所有值 | rdd.lookup(3) | [4, 6] |