Rdd详解

RDD 详解

1. RDD概述

RDD(Resilient Distributed Dataset)叫做分布式数据集,是Spark中最基本的数据抽象,它代表一个不可变、可分区、里面的元素可并行计算的集合。RDD具有数据流模型的特点:自动容错、位置感知性调度和可伸缩性。RDD允许用户在执行多个查询时显式地将工作集缓存在内存中,后续的查询能够重用工作集,这极大地提升了查询速度。

2. RDD属性

2.1 分片: 即数据集的基本组成单位。对于RDD来说,每个分片都会被一个计算任务处理,并决定并行计算的粒度。用户可以在创建RDD时指定RDD的分片个数,如果没有指定,那么就会采用默认值。默认值就是程序所分配到的CPU Core的数目。

2.2 函数: Spark中RDD的计算是以分片为单位的,每个RDD都会实现compute函数以达到这个目的。compute函数会对迭代器进行复合,不需要保存每次计算的结果。

2.3 依赖关系: RDD的每次转换都会生成一个新的RDD,所以RDD之间就会形成类似于流水线一样的前后依赖关系。在部分分区数据丢失时,Spark可以通过这个依赖关系重新计算丢失的分区数据,而不是对RDD的所有分区进行重新计算。

2.4 RDD的分片函数(Partitioner):
当前Spark中实现了两种类型的分片函数,一个是基于哈希的HashPartitioner,另外一个是基于范围的RangePartitioner。只有对于于key-value的RDD,才会有Partitioner,非key-value的RDD的Parititioner的值是None。Partitioner函数不但决定了RDD本身的分片数量,也决定了parent RDD Shuffle输出时的分片数量。

3. RDD分区

分区是RDD内部并行计算的一个计算单元,RDD的数据集在逻辑上被划分为多个分片,每一个分片称为分区,分区的格式决定了并行计算的粒度,而每个分区的数值计算都是在一个任务中进行的,因此任务的个数,也是由RDD(准确来说是作业最后一个RDD)的分区数决定。

RDD分区的一个分区原则:尽可能是分区的个数等于集群核数目

无论是本地模式、Standalone模式、YARN模式或Mesos模式,我们都可以通过spark.default.parallelism来配置其默认分区个数,若没有设置该值,则根据不同的集群环境确定该值,本地模式:默认为本地机器的CPU数目,若设置了local[N],则默认为N,Apache Mesos:默认的分区数为8,Standalone或YARN:默认取集群中所有核心数目的总和,或者2,取二者的较大值。

4. RDD算子

4.1 RDD中的所有转换都是延迟加载的,也就是说,它们并不会直接计算结果。相反的,它们只是记住这些应用到基础数据集(例如一个文件)上的转换动作。只有当发生一个要求返回结果给Driver的动作时,这些转换才会真正运行。这种设计让Spark更加有效率地运行。

4.2 常用的Transformation

RDD 创建
方式一:
val data = Array(3,2,54,62,4)
val rdd = sc.parallelize(data)
方式二:
val rdd1 = sc.textFile(“c://data.txt”) //指定本地目录下文件
val rdd1 = sc.textFile(“hdfs://master:9000/input/ data.txt”) //指定HDFS文件
val rdd1 = sc.textFile("/input /*.txt") //含通配符的路径

map(fun)
fun这个函数用于RDD中的每一个元素,将函数的返回结果作为结果RDD中对应元素

mapPartitions(fun)
rdd的mapPartitions是map的一个变种,它们都可进行分区的并行处理。两者的主要区别是调用的粒度不一样:map的输入变换函数是应用于RDD中每个元素,而mapPartitions的输入函数是应用于每个分区,假设一个rdd有10个元素,分成3个分区。如果使用map方法,map中的输入函数会被调用10次;而使用mapPartitions方法的话,其输入函数会只会被调用3次,每个分区调用1次在大数据集情况下的资源初始化开销和批处理处理,都要初始化一个耗时的资源,然后使用,比如数据库连接。mapPartitons的开销要小很多,也便于进行批处理操作。

mapValues [Pair]相当于是map之对key-value 的value进行处理
mapValues 用于处理key-value类型的RDD,每次处理一个key-value对mapValues 处理的是key-value中的value,处理完value之后,
就会返回一个key-value类型的数据,返回到新RDD中去
val a = sc.parallelize(List(“dog”, “tiger”, “lion”, “cat”,“panther”, “eagle”,“cat”,“cat”), 2)
val b = a.map(x=>(x,x.length))
b.mapValues(x=>x+10).collect
res8: Array[(String, Int)] = Array((dog,13), (tiger,15), (lion,14), (cat,13), (panther,17), (eagle,15), (cat,13), (cat,13))

keys
keys 获取RDD中元组的key,这些key可以重复出现
val a = sc.parallelize(List(“dog”, “tiger”, “lion”, “cat”, “panther”, “eagle”,“cat”,“cat”), 2)
val b = a.map(x=>(x,x.length))
b.keys.collect
res9: Array[String] = Array(dog, tiger, lion, cat, panther, eagle, cat, cat)

filter(func)
将RDD满足该函数的元素放入新的RDD中返回

**flatMap(func)**方法可以实现对每个输入元素生成多个输出元素,返回一个返回值序列的迭代器。其一个简单用途就是把输入的字符串切分为单词。
val lines=sc.parallelize(List(“hello word”,“hi”,“I’m back”))
val words=lines.flatMap(line=>line.split(" "))
words.collect

union(otherDataset)
会返回一个包含两个RDD中所有元素的RDD,包含重复数据。
rdd1.union(rdd2)

distinct([numTasks]))
生成一个只包含不同元素的一个新的RDD。开销很大
rdd1.diistinct

intersection(otherRDD) (注意全部是小写)
只返回两个RDD中都有的元素。可能会去掉所有的重复元素

subtract(otherRDD)
返回只存在第一个RDD中而不存在第二个RDD中的所有的元素组成的RDD。也需要网络混洗

join(otherDataset, [numTasks])

groupBy(fun)
groupBy 将RDD中的数据按照指定的函数和分区数量,来进行分组。
val a = sc.parallelize(1 to 9, 3)
//groupBy的第一个参数是一个函数,用于指定分组条件。分类标签由条件返回值给定
//这里会根据条件返回 “even” 和 “odd”
a.groupBy(x => { if (x % 2 == 0) “even” else “odd” }).collect
res1: Array((even,CompactBuffer(2, 8, 4, 6)), (odd,CompactBuffer(5, 1, 3, 7, 9)))

//这里的返回标签为 0 ,1 ,2
a.groupBy(x =>(x % 3)).collect
res2:Array((0,CompactBuffer(3, 9, 6)), (1,CompactBuffer(4, 1, 7)), (2,CompactBuffer(2, 8, 5)))
//groupBy中的第二个参数是指定,分组后将结果存储在几个分区中,默认分区数量和RDD元素分区数量相等
a.groupBy(x => myfunc(x), 3).collect
res2: Array((0,ArrayBuffer(2, 4, 6, 8)), (1,ArrayBuffer(1, 3, 5, 7, 9)))

groupByKey([numTasks])
groupByKey 和 groupBy 非常相似,不提供函数功能,只是按照key来进行分组,相同的key分在一组,相比于groupBy 要简单
val a = sc.parallelize(List(“dog”, “tiger”, “lion”, “cat”, “spider”, “eagle”), 2)
//生成一个以单词长度作为key,单词作为value的 元组
val b = a.keyBy(_.length)
//groupByKey不提供函数功能,直接按照Key进行分类
b.groupByKey.collect
res1: Array[(Int, Seq[String])] = Array((4,ArrayBuffer(lion)), (6,ArrayBuffer(spider)), (3,ArrayBuffer(dog, cat)), (5,ArrayBuffer(tiger, eagle)))

sortBy(func,[ascending], [numTasks])
对RDD进行排序
第一个参数是一个函数,该函数的也有一个带T泛型的参数,返回类型和RDD中元素的类型是一致的;
第二个参数是ascending,从字面的意思大家应该可以猜到,是的,这参数决定排序后RDD中的元素是升序还是降序,默认是true,也就是升序;
第三个参数是numPartitions,该参数决定排序后的RDD的分区个数,默认排序后的分区个数和排序之前的个数相等,即为this.partitions.size。

sortByKey([ascending], [numTasks])
Key-Value形式的RDD,并对Key进行排序

4.3 Action

reduce(fun)
reduce将RDD中元素两两传递给输入函数,同时产生一个新的值,新产生的值与RDD中下一个元素再被传递给输入函数直到最后只有一个值为止。
val rdd=sc.parallelize(List(1,2,3,3))
val sum=rdd.reduce((x,y)=>x+y) 求和

collect()
一般在filter或者足够小的结果的时候,再用collect封装返回一个数组

reduceByKey(fun)
先根据相同的 key 进行分组,然后在相同的 key 中进行聚合,聚合形式和 reduce 相同
reduceByKey 先根据相同的 key 进行分组,然后在相同的 key 中进行聚合,聚合形式和 reduce 相同
val a = sc.parallelize(List(“dog”, “tiger”, “lion”, “cat”, “panther”, “eagle”,“cat”,“cat”), 2)
val b = a.map(x=>(x,x.length))
b.reduceByKey(+).collect
res0: Array[(String, Int)] = Array((panther,7), (dog,3), (eagle,5), (lion,4), (cat,9), (tiger,5))

val rdd1 = sc.parallelize(List((“tom”, 1), (“jerry”, 3), (“kitty”, 2), (“shuke”, 1)))
val rdd2 = sc.parallelize(List((“jerry”, 2), (“tom”, 3), (“shuke”, 2), (“kitty”, 5)))
val rdd3 = rdd1.union(rdd2)
//按key进行聚合
val rdd4 = rdd3.reduceByKey(_ + _)
rdd4.collect
//按value的降序排序
val rdd5 = rdd4.map(t => (t._2, t._1)).sortByKey(false).map(t => (t._2, t._1))
rdd5.collect

count()
返回是dataset中的element的个数

first()
返回的是dataset的第一个元素

take(n)
返回前n个elements

saveAsTextFile(path)
把dataset写到一个textfile中,或者hdfs

saveAsSequenceFile(path)
只能用在key-value对上,然后生成SequenceFile写到本地或者hadoop文件系统

saveAsObjectFile(path)
把dataset写到一个java序列化的文件中,用SparkContext。objectFile()装载

countByKey()
返回的是key对应的个数的一个map,作用于RDD

foreach(func)
对dataset中的每个元素都使用func

max,min
max 返回RDD中最大/小的元素,如果是元组,那么返回key最大/小的元素

5. RDD的依赖关系

5.1 RDD和它依赖的父RDD(s)的关系有两种不同的类型,即窄依赖(narrow dependency)和宽依赖(wide dependency)
5.2 窄依赖指的是每一个父RDD的Partition最多被子RDD的一个Partition使用
总结:窄依赖我们形象的比喻为独生子女
5.3 宽依赖指的是多个子RDD的Partition会依赖同一个父RDD的Partition
总结:窄依赖我们形象的比喻为超生

6. RDD的缓存

Spark速度非常快的原因之一,就是在不同操作中可以在内存中持久化或缓存个数据集。当持久化某个RDD后,每一个节点都将把计算的分片结果保存在内存中,并在对此RDD或衍生出的RDD进行的其他动作中重用。这使得后续的动作变得更加迅速。RDD相关的持久化和缓存,是Spark最重要的特征之一。可以说,缓存是Spark构建迭代式算法和快速交互式查询的关键。

7. idea 创建scala工程在new的时候没有scala class 解决方案"

1.ideal 开发scala,首先 要在setting里面下载一个插件”scala“

2.然后在project structure -->Global Libraries => +号 =>选择本机scala的安装路径 =>apply=>ok

3.最后在创建文件的时候, new后有了Scala class

  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值