一、算子合集
1.常用算子
2.算子的使用限制
某些算子,例如reduceByKey必须是一个[k,v]结构才能使用
解决方法:
封装成tuple格式等
二、RDD与DataFrame之间的转换
三、RDD泛型转换问题
1.RDD[ Iterable[ T ] ] =>RDD[ T ]
场景:
对RDD[T] 进行groupBy分组处理后需要还原成RDD[T](实际上应该是Rdd[key,Iterable[T])这里只考虑核心问题
代码:
val rdd:RDD[Iterable[T]]
val transRdd:Rdd[T] = rdd.flatMap(item=>{
data:Iterable[T].toArray
})
结论:其实很简单,flatMap能够展开内部的数组,合并起来,如果使用map会变成Rdd[Array[T]]
2.RDD[Row]与RDD[ T ]之间的转换
场景:
1.rdd[row]=>rdd[T] 利用spark.sql取得dataFrame以后转换成Rdd,此时的Rdd为Rdd[Row]
2.rdd[T]=>rdd[row] 将RDD[T]利用spark.createTempView注册成视图
1.代码
val rdd:rdd[row]
val transRdd:Rdd[T] = rdd.map(item=>{
new T(item.getString(0),item.getInt(1).....,item.getString(item.length-1))
})
2.代码
val rdd:rdd[T]
val transRdd:Rdd[Row] = rdd.map(item=>{
Row(item.elem1,item.elem2,......,item.elemN)
})
结论: 直接在map内部构造实例即可
四、将RDD转换成各种集合 (RDD算子中变量修改失效问题)
场景:需要将RDD的数据输出到给其他模块/函数
1.将RDD[T]转换成List[T]
错误演示:
def fun(rdd:Rdd[T]):List[T]={
val listBuffer = ListBuffer[T]
rdd.foreach(item=>{
listBuffer.append(item)
})
listBuffer.toList
}
错误原因:spark算子内的变量实际上是外部变量的副本,对其修改不能改变外部的变量。其中原理很简单,rdd是分布在多个机器上的,其算子也是如此,普通变量不能简单的在各个机器中同时修改。
正确操作 1:使用累加器
def fun(sparkContext:SparkContext,rdd:Rdd[T]):List[T]={
//实例化累加器
val acc = new sparkContext.collectionAccumulator[T]("name")
rdd.foreach(item=>{
acc.add(item)
})
//取出累加器内的值,隐式转换成了List
acc.value
}
结论:Accumulator是spark中的累加器,顾名思义该变量只能增加,只有driver能获取到Accumulator的值(使用value方法),Task只能对其做增加操作
正确操作 2:使用collect算子
def fun(rdd:Rdd[T]):List[T]={
rdd.collect().toList()
}