map
rdd.map(func):RDD,对rdd集合中的每一个元素,都作用一次该func函数,之后返回值为生成元素构成的一个新的RDD。
listRDD.map(num => num * 7)
mapPartitions/mapPartitionsWithIndex
/**
* map(p: A => B)
* 对集合中的每一条记录操作,将元素A转化为元素B
* mapPartitions(p: Iterator[A] => Iterator[B])
* 上面的map操作,一次处理一条记录;而mapPartitions一次性处理一个partition分区中的数据
* 注意:
* 虽说mapPartitions的执行性能要高于map,但是其一次性将一个分区的数据加载到执行内存空间,如果该分区数据集比较大,存在OOM的风险
* mapPartitionsWithIndex((index, p: Iterator[A] => Iterator[B]))
* 该操作比mapPartitions多了一个index,代表就是后面p所对应的分区编号
*
* rdd的分区编号,命名规范,如果又N个分区,分区编号就从0,。。,N-1
*/
//mapPartitions
def mapPartitionsFunction(sc:SparkContext): Unit ={
val arr=1 to 10
val rdd:RDD[Int] = sc.parallelize(arr)
var a=rdd.mapPartitions(partition=>{
val list = partition.toList
println(list.mkString(","))
list.map(_*2).toIterator//本来只执行这里就行,但因为我想打印一下,而迭代器遍历一次就失效了,所以转成list
})
a.foreach(println)
}
//mapPartitionsWithIndex
def mapPartitionsWithIndexFunction(sc:SparkContext): Unit ={
val arr=1 to 10
val rdd:RDD[Int] = sc.parallelize(arr)
rdd.mapPartitionsWithIndex((index,partition)=>{
val list = partition.toList
println(s"分区${index}的数据为:${list.mkString(",")}")
list.map(_*2).toIterator
}).count()
}
flatMap
rdd.flatMap(func):RDD ==>rdd集合中的每一个元素,都要作用func函数,返回0到多个新的元素,这些新的元素共同构成一个新的RDD。所以和上述map算子进行总结:
map操作是一个one-2-one的操作
flatMap操作是一个one-2-many的操作
filter
rdd.filter(func):RDD ==> 对rdd中的每一个元素操作func函数,该函数的返回值为Boolean类型,保留返回值为true的元素,共同构成一个新的RDD,过滤掉哪些返回值为false的元素。
sc.parallelize(list) .filter(_ % 2 == 0)
sample
sample(withReplacement, fraction, seed):随机抽样算子
sample主要工作就是为了来研究数据本身,去代替全量研究会出现类似数据倾斜(dataSkew)等问题,无法进行全量研究,只能用样本去评估整体。
首先得要知道这三个参数是啥意思
withReplacement:抽样的方式,true有放回抽样, false为无返回抽样
fraction: 抽样比例,取值范围就是0~1
seed: 抽样的随机数种子,有默认值,通常也不需要传值
案例:从10w个数中抽取千分之一进行样本评估
def sampleMapOps(sc:SparkContext): Unit = {
val listRDD = sc.parallelize(1 to 100000)
var sampledRDD = listRDD.sample(true, 0.001)
println("样本空间的元素个数:" + sampledRDD.count())
sampledRDD = listRDD.sample(false, 0.001)
println("样本空间的元素个数:" + sampledRDD.count())
}
union
/**
* rdd1.union(rdd2)
* 相当于sql中的union all,进行两个rdd数据间的联合,需要说明一点是,该union是一个窄依赖操作,
* rdd1如果又N个分区,rdd2又M个分区,那么union之后的分区个数就为N+M
*/
def unionfun(sc:SparkContext): Unit ={
//给两个rdd,每个rdd设置两个分区测试,结果union后 应该有四个分区
val value = sc.parallelize(1 to 10,2)
value.mapPartitionsWithIndex((index,partition)=>{
val list = partition.toList
println(s"分区${index}-->${list.mkString(",")}")
list.toIterator
}).count()
println("----------1-----------")
val value1 = sc.parallelize(20 to 30,2)
value.mapPartitionsWithIndex((index,partition)=>{
val list = partition.toList
println(s"分区${index}-->${list.mkString(",")}")
list.toIterator
}).count()
println("---------2---------")
val value2 = value.union(value1)
value2.mapPartitionsWithIndex((index,partition)=>{
val list = partition.toList
println(s"分区${index}-->${list.mkString(",")}")
list.toIterator
}).count()//写上action算子,触发执行
}
join
sparkcore中支持的连接有:笛卡尔积、内连接join,外连接(左、右、全)
要想两个RDD进行连接,那么这两个rdd的数据格式,必须是k-v键值对的,其中的k就是关联的条件,也就是sql中的on连接条件。
//join,leftOuterJoin,rightOuterJoin
def join(sc:SparkContext): Unit ={