Scala笔记(四):RDD相关API函数汇总

RDD简单介绍

RDD

RDD是Spark中的抽象数据结构类型,任何数据在Spark中都被表示为RDD。从Scala编程的角度看,可以将其简单看成是一个数组。与我们理解数组的区别是,RDD中的数据分区存储,不同分区的数据就分布在不同的机器上,可被并行处理。因此,Spark应用程序所做的无非是把需要处理的数据转换为RDD,然后对RDD进行一系列的变换和操作从而得到结果。

创建RDD

RDD可从普通数组创建,也可由系统目录或HDFS中的文件创建。
举例:从普通数组创建RDD,里面包含了1到9这9个数字,它们分别在3个分区中。

scala> val a = sc.parallelize(1 to 9, 3)
a: org.apache.spark.rdd.RDD[Int] = ParallelCollectionRDD[1] at parallelize at :12

举例:读取文件README.md来创建RDD,文件中的每一行就是RDD中的一个元素

scala> val b = sc.textFile("README.md")
b: org.apache.spark.rdd.RDD[String] = MappedRDD[3] at textFile at :12

注意以上例子中要直接在shell中执行需要对spark进行配置,指定一个实例。
构造了RDD对象了,接下来就是如何操作RDD对象。RDD的操作分为变换操作(transformation)和行动操作(action),RDD之所以将操作分成这两类这是和RDD惰性(lazy)运算有关,当RDD执行变换操作时候,实际计算并没有被执行,只有当RDD执行行动操作时候才会触发任务提交,执行相应的计算操作。

变换操作

  • map():参数是函数,函数应用于RDD每一个元素,返回值是新的RDD

  • flatMap():参数是函数,函数应用于RDD每一个元素,将元素数据进行拆分,变成迭代器,返回值是新的RDD

  • filter():参数是函数,函数会过滤掉不符合条件的元素,返回值是新的RDD

  • zip():把两个列表的元素合成一个由元素对组成的列表里

  • partition():根据函数的返回值对列表进行拆分

  • find():返回集合里第一个匹配结果的元素

  • flatten:用于把嵌套的结构展开

  • distinct():没有参数,将RDD里的元素进行去重操作

  • union():参数是RDD,生成包含两个RDD所有元素的新RDD

  • intersection():参数是RDD,求出两个RDD的共同元素

  • subtract():参数是RDD,将原RDD里和参数RDD里相同的元素去掉

  • cartesian():参数是RDD,求两个RDD的笛卡儿积

//zip
scala> Array(1, 2, 3).zip(Array("one", "two", "three"))
res6: Array[(Int, java.lang.String)] = Array((1,one), (2,two), (3,three))


//partition
scala> val numbers = Array(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)
numbers: Array[Int] = Array(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)

scala> numbers.partition(_ % 2 == 0)
res7: (Array[Int], Array[Int]) = (Array(2, 4, 6, 8, 10),Array(1, 3, 5, 7, 9))

//find
scala> numbers.find(_ > 5)
res8: Option[Int] = Some(6)

//flatten
scala> Array(Array(1, 2), Array(3, 4))
res17: Array[Array[Int]] = Array(Array(1, 2), Array(3, 4))

scala> Array(Array(1, 2), Array(3, 4)).flatten
res18: Array[Int] = Array(1, 2, 3, 4)

行动操作

  • collect():返回RDD所有元素

  • count():RDD里元素个数

  • countByValue():各元素在RDD中出现次数

  • reduce():并行整合所有RDD数据,例如求和操作

  • fold(0)(func):和reduce功能一样,不过fold带有初始值

  • foreach(func):对RDD和map一样对每个元素都使用特定函数,无返回值。

  • take(n):返回结果的前n个元素

  • first():返回据集的第一个元素(类似于take(1))

  • saveAsTextFile(path):据集的元素,以textfile的形式,保存到本地文件系统,hdfs或者任何其它hadoop支持的文件系统


二元组RDD常用API

下面是二元组RDD或K-V对RDD的API,同样分类:

1. 变换操作:

reduceByKey:合并具有相同键的值;
groupByKey:对具有相同键的值进行分组;
keys:返回一个仅包含键值的RDD;
values:返回一个仅包含值的RDD;
sortByKey:返回一个根据键值排序的RDD;
flatMapValues:针对Pair RDD中的每个值应用一个返回迭代器的函数,然后对返回的每个元素都生成一个对应原键的键值对记录;
mapValues:对Pair RDD里每一个值应用一个函数,但是不会对键值进行操作;
combineByKey:使用不同的返回类型合并具有相同键的值;
subtractByKey:操作的RDD我们命名为RDD1,参数RDD命名为参数RDD,剔除掉RDD1里和参数RDD中键相同的元素;
join:对两个RDD进行内连接,在类型(K,V)和(K,W)类型的据集上用,返回一个(K,(V,W)),每个key中的所有元素都在一起的据集;
rightOuterJoin:对两个RDD进行连接操作,第一个RDD的键必须存在,第二个RDD的键不再第一个RDD里面有那么就会被剔除掉,相同键的值会被合并;
leftOuterJoin:对两个RDD进行连接操作,第二个RDD的键必须存在,第一个RDD的键不再第二个RDD里面有那么就会被剔除掉,相同键的值会被合并;
cogroup:将两个RDD里相同键的数据分组在一起

2. 行动操作

countByKey:对每个键的元素进行分别计数;
collectAsMap:将结果变成一个map;
lookup:在RDD里使用键值查找数据
  
  
接下来是不常用的RDD操作:
变换操作:
sample:对RDD采样;
行动操作:
take(num):返回RDD里num个元素,随机的;
top(num):返回RDD里最前面的num个元素,这个方法实用性还比较高;
takeSample:从RDD里返回任意一些元素;
sample:对RDD里的数据采样;
takeOrdered:从RDD里按照提供的顺序返回最前面的num个元素


常用易混的API

map

是对RDD中的每个元素都执行一种指定的映射方式(可理解为函数映射:x->f(x))来产生一个新的RDD。任何原RDD中的元素在新RDD中有且只有一个元素与之对应。
举例:

scala> val a = sc.parallelize(1 to 9, 3)
scala> val b = a.map(x => x*2)
scala> a.collect
res10: Array[Int] = Array(1, 2, 3, 4, 5, 6, 7, 8, 9)
scala> b.collect
res11: Array[Int] = Array(2, 4, 6, 8, 10, 12, 14, 16, 18)

mapPartitions

mapPartitions是map的一个变种。map的输入函数是应用于RDD中每个元素,而mapPartitions的输入函数是应用于每个分区,也就是把每个分区中的内容作为整体来处理的。
其函数定义为:
def mapPartitions[U: ClassTag](f: Iterator[T] => Iterator[U], preservesPartitioning: Boolean = false): RDD[U]
f即为输入函数,它处理每个分区里面的内容。每个分区中的内容将以Iterator[T]传递给输入函数f,f的输出结果是Iterator[U]。最终的RDD由所有分区经过输入函数处理后的结果合并起来的。
举例:

scala> val a = sc.parallelize(1 to 9, 3)
scala> def myfunc[T](iter: Iterator[T]) : Iterator[(T, T)] = {
    var res = List[(T, T)]() 
    var pre = iter.next while (iter.hasNext) {
        val cur = iter.next; 
        res .::= (pre, cur) pre = cur;
    } 
    res.iterator
}
scala> a.mapPartitions(myfunc).collect
res0: Array[(Int, Int)] = Array((2,3), (1,2), (5,6), (4,5), (8,9), (7,8))

上述例子中的函数myfunc把分区中一个元素和它的下一个元素组成一个Tuple。分区中3、6和9是最后一个元素没有下一个元素(iterator是倒过来遍历的?)。
mapPartitions类似的,如mapPartitionsWithContext,mapPartitionsWithIndex。

mapValues

mapValues简单点想就是支队RDD中Kev-Value的Value做函数映射,RDD中的Key保持不变,与新的Value一起组成新的RDD中的元素。因此,该函数只适用于元素为KV对的RDD。
举例:

scala> val a = sc.parallelize(List("dog", "tiger", "lion", "cat", "panther", " eagle"), 2)
scala> val b = a.map(x => (x.length, x))
scala> b.mapValues("x" + _ + "x").collect
res5: Array[(Int, String)] = Array((3,xdogx), (5,xtigerx), (4,xlionx),(3,xcatx), (7,xpantherx), (5,xeaglex))

mapWith

mapWith是map的另外一种变化,map只需要一个输入函数,而mapWith有两个输入函数。它的定义如下:
def mapWith[A: ClassTag, U: ](constructA: Int => A, preservesPartitioning: Boolean = false)(f: (T, A) => U): RDD[U]
第一个函数constructA是把RDD的partition index(index从0开始)作为输入,输出为新类型A;
第二个函数f是把二元组(T, A)作为输入(其中T为原RDD中的元素,A为第一个函数的输出),输出类型为U。
举例:把partition index 乘以10,然后加上2作为新的RDD的元素。

val x = sc.parallelize(List(1,2,3,4,5,6,7,8,9,10), 3) 
x.mapWith(a => a * 10)((a, b) => (b + 2)).collect 
res4: Array[Int] = Array(2, 2, 2, 12, 12, 12, 22, 22, 22, 22)

flatMap

与map类似,区别是原RDD中的元素经map处理后只能生成一个元素,而原RDD中的元素经flatmap处理后可生成多个元素来构建新RDD。
举例:对原RDD中的每个元素x产生y个元素(从1到y,y为元素x的值)

scala> val a = sc.parallelize(1 to 4, 2)
scala> val b = a.flatMap(x => 1 to x)
scala> b.collect
res12: Array[Int] = Array(1, 1, 2, 1, 2, 3, 1, 2, 3, 4)

reduce

reduce将RDD中元素两两传递给输入函数,同时产生一个新的值,新产生的值与RDD中下一个元素再被传递给输入函数直到最后只有一个值为止。
举例:

scala> val c = sc.parallelize(1 to 10)
scala> c.reduce((x, y) => x + y)
res4: Int = 55

上述例子实现对RDD中的元素求和。

reduceByKey

reduceByKey是对元素为KV对的RDD中Key相同的元素的Value进行reduce,因此,Key相同的多个元素的值被reduce为一个值,然后与原RDD中的Key组成一个新的KV对。
举例:

scala> val a = sc.parallelize(List((1,2),(3,4),(3,6)))
scala> a.reduceByKey((x,y) => x + y).collect
res7: Array[(Int, Int)] = Array((1,2), (3,10))

参考

http://www.cnblogs.com/sharpxiajun/p/5506822.html
http://homepage.cs.latrobe.edu.au/zhe/ZhenHeSparkRDDAPIExamples.html
https://www.cnblogs.com/vincent-hv/p/3297542.html

阅读更多
版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/m0_37343696/article/details/81592931
个人分类: IDEA/Scala/Spark
想对作者说点什么? 我来说一句

没有更多推荐了,返回首页

关闭
关闭
关闭