@value默认值_SparkCoreRDD转换(value)

在 RDD 上支持 2 种操作:

1.transformation

从一个已知的 RDD 中创建出来一个新的 RDD 例如: map就是一个transformation.

2.action

在数据集上计算结束之后, 给驱动程序返回一个值. 例如: reduce就是一个action.

在 Spark 中几乎所有的transformation操作都是懒执行的(lazy), 也就是说transformation操作并不会立即计算他们的结果, 而是记住了这个操作.

只有当通过一个action来获取结果返回给驱动程序的时候这些转换操作才开始计算.

这种设计可以使 Spark 运行起来更加的高效.

默认情况下, 你每次在一个 RDD 上运行一个action的时候, 前面的每个transformed RDD 都会被重新计算.

但是我们可以通过persist (or cache)方法来持久化一个 RDD 在内存中, 也可以持久化到磁盘上, 来加快访问速度. 后面有专门的章节学习这种持久化技术.

根据 RDD 中数据类型的不同, 整体分为 2 种 RDD:

1.Value类型

2.Key-Value类型(其实就是存一个二维的元组)

Value 类型
map(func)

作用: 返回一个新的 RDD, 该 RDD 是由原 RDD 的每个元素经过函数转换后的值而组成. 就是对 RDD 中的数据做转换.

559cf7dd55be2aa15645dc31811a8a3f.gif

案例:

创建一个包含1-10的的 RDD,然后将每个元素*2形成新的 RDD

scala > val rdd1 = sc.parallelize(1 to 10)// 得到一个新的 RDD, 但是这个 RDD 中的元素并不是立即计算出来的scala> val rdd2 = rdd1.map(_ * 2)// 开始计算 rdd2 中的元素, 并把计算后的结果传递给驱动程序scala> rdd2.collect

9a4eb2d342faeefb03ce0dc8c5f7b982.png

mapPartitions(func)

作用: 类似于map(func), 但是是独立在每个分区上运行.所以:Iterator=> Iterator

假设有N个元素,有M个分区,那么map的函数的将被调用N次,而mapPartitions被调用M次,一个函数一次处理所有分区。

scala> val source = sc.parallelize(1 to 10)scala> source.mapPartitions(it => it.map(_ * 2))scala> res4.collect

32db2098fd194e1888f9b4d3cc2651ca.png

f05bcdb741993171eedc2e068bcd31a2.png

mapPartitionsWithIndex(func)

作用: 和mapPartitions(func)类似. 但是会给func多提供一个Int值来表示分区的索引. 所以func的类型是:(Int, Iterator) => Iterator

scala> val rdd1 = sc.parallelize(Array(10,20,30,40,50,60))scala> rdd1.mapPartitionsWithIndex((index, items) => items.map((index, _)))scala> res7.collect

923b3084b20fb46254590bd5c1b09d1c.png

map()mapPartitions()的区别

2.map():每次处理一条数据。

3.mapPartitions():每次处理一个分区的数据,这个分区的数据处理完后,原 RDD 中该分区的数据才能释放,可能导致 OOM。

4.开发指导:当内存空间较大的时候建议使用mapPartitions(),以提高处理效率。

flatMap(func)

作用: 类似于map,但是每一个输入元素可以被映射为 0 或多个输出元素(所以func应该返回一个序列,而不是单一元素 T => TraversableOnce[U])

251c7bc5e2b0518af5640e53abc79e40.gif

创建一个元素为 1-5 的RDD,运用 flatMap创建一个新的 RDD,新的 RDD 为原 RDD 每个元素的 平方和三次方 来组成 1,1,4,8,9,27..

scala> val rdd1 = sc.parallelize(Array(1,2,3,4,5))scala> rdd1.flatMap(x => Array(x * x, x * x * x))scala> res9.collect

e12d9f5fda12ec255b5f1fff436dbf26.png

glom()

作用: 将每一个分区的元素合并成一个数组,形成新的 RDD 类型是RDD[Array[T]]

创建一个 4 个分区的 RDD,并将每个分区的数据放到一个数组

scala> var rdd1 = sc.parallelize(Array(10,20,30,40,50,60), 4)scala> rdd1.glom.collect

83d73cd060466d42ba07e7f10c0be530.png

groupBy(func)

作用:

按照func的返回值进行分组.

func返回值作为 key, 对应的值放入一个迭代器中. 返回的 RDD: RDD[(K, Iterable[T])

每组内元素的顺序不能保证, 并且甚至每次调用得到的顺序也有可能不同.

创建一个 RDD,按照元素的奇偶性进行分组

scala> val rdd1 = sc.makeRDD(Array(1, 3, 4, 20, 4, 5, 8))   scala> rdd1.groupBy(x => if(x % 2 == 1) "odd" else "even")scala> res12.collect

dfd6fc200b97ce2dcf78cb2357544fd0.png

filter(func)

作用: 过滤. 返回一个新的 RDD 是由func的返回值为true的那些元素组成

创建一个 RDD(由字符串组成),过滤出一个新 RDD(包含“xiao”子串)

scala> val names = sc.parallelize(Array("xiaoli", "laoli", "laowang", "xiaocang", "xiaojing", "xiaokong"))scala> names.filter(_.contains("xiao"))scala> res14.collect

df0f238a044182330a1aa1e3fc9a4f93.png

sample(withReplacement, fraction, seed)

作用:

5.以指定的随机种子随机抽样出比例为fraction的数据,(抽取到的数量是: size * fraction). 需要注意的是得到的结果并不能保证准确的比例.

6.withReplacement表示是抽出的数据是否放回,true为有放回的抽样,false为无放回的抽样. 放回表示数据有可能会被重复抽取到, false 则不可能重复抽取到. 如果是false, 则fraction必须是:[0,1], 是 true 则大于等于0就可以了.

7.seed用于指定随机数生成器种子。 一般用默认的, 或者传入当前的时间戳

不放回抽样
scala> val rdd1 = sc.parallelize(1 to 10)scala> rdd1.sample(false, 0.5).collect

b98b1beba5cd0b62dbc3f14c21a54b92.png

放回抽样

scala> rdd1.sample(true, 2).collect

7f0cfdd959f25378437b6bb0cb3eac37.png

distinct([numTasks]))

作用:

对 RDD 中元素执行去重操作. 参数表示任务的数量.默认值和分区数保持一致.

scala> val rdd1 = sc.parallelize(Array(10,10,2,5,3,5,3,6,9,1))scala> rdd1.distinct().collect

e267a5801a0e1f30330df1ba3777d763.png

coalesce(numPartitions)

作用: 缩减分区数到指定的数量,用于大数据集过滤后,提高小数据集的执行效率。

scala> val rdd1 = sc.parallelize(0 to 100, 5)scala> rdd1.partitions.length// 减少分区的数量至 2 scala> rdd1.coalesce(2)scala> res4.partitions.length

0078465431443b43fafb11195289abc7.png

注意:

第二个参数表示是否shuffle, 如果不传或者传入的为false, 则表示不进行shuffer, 此时分区数减少有效, 增加分区数无效.

repartition(numPartitions)

作用: 根据新的分区数, 重新 shuffle 所有的数据, 这个操作总会通过网络.

新的分区数相比以前可以多, 也可以少

scala> val rdd1 = sc.parallelize(0 to 100, 5)scala> rdd1.repartition(3)scala> res6.partitions.lengthscala> rdd1.repartition(10)scala> res7.partitions.length

806130d88e36ade13d3733e671154882.png

5f8219b97df777e1ba08475d63fabfc8.png

coalascerepartition的区别

8.coalesce重新分区,可以选择是否进行shuffle过程。由参数shuffle: Boolean = false/true决定。

9.repartition实际上是调用的coalesce,进行shuffle。源码如下:

def repartition(numPartitions: Int)(implicit ord: Ordering[T] = null): RDD[T] = withScope {coalesce(numPartitions, shuffle = true)}

10.如果是减少分区, 尽量避免 shuffle

sortBy(func,[ascending], [numTasks])

作用: 使用func先对数据进行处理,按照处理后结果排序,默认为正序。

scala> val rdd1 = sc.parallelize(Array(1,3,4,10,4,6,9,20,30,16))scala> rdd1.sortBy(x => x).collectscala> rdd1.sortBy(x => x, true).collect// 不用正序scala> rdd1.sortBy(x => x, false).collect

a3a047aaeef59ac072c0154115aadd5a.png

pipe(command, [envVars])

作用: 管道,针对每个分区,把 RDD 中的每个数据通过管道传递给shell命令或脚本,返回输出的RDD。一个分区执行一次这个命令. 如果只有一个分区, 则执行一次命令.

注意:

脚本要放在 worker 节点可以访问到的位置

步骤1: 创建一个脚本文件pipe.sh

文件内容如下:

echo "hello"while read line;do    echo ">>>"$linedone

c5c1485f03606f83ab8f1b7609e227cd.png

步骤2: 创建只有 1 个分区的RDD
scala> val rdd1 = sc.parallelize(Array(10,20,30,40), 1)scala> rdd1.pipe("/pipe.sh").collect

fa61e5615355efddddd86b95d89c41b3.png

步骤3: 创建有 2 个分区的 RDD
scala> val rdd1 = sc.parallelize(Array(10,20,30,40), 2)scala> rdd1.pipe("/pipe.sh").collect

cd797ac7c8af54c497001756e271b9f6.png

总结: 每个分区执行一次脚本, 但是每个元素算是标准输入中的一行
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值