Spark 当中map,flatMap,mapPartitions的区别以及示例

这几天学习看了map以及flatMap还有mapPartitions,然后写一篇博文记录一哈,以免自己忘了,如果有写错的地方,一定要不留情面的指出来!

Spark 当中map,flatMap,mapPartitions
map:对集合中每个元素进行操作。
flatMap:对集合中每个元素进行操作然后再扁平化(打平)。
mapPartitions:与map类似,函数会对每个分区中的一组数据进行相应的操作(把每个分区的数据当成map当中每个元素,可以着了类比)。

接下来就详细看一下每个方法传什么参数,然后返回的结果有什么不同。

1.map

接口定义如下:

def map[U](f : scala.Function1[T, U])(implicit evidence$3 : scala.reflect.ClassTag[U]) : org.apache.spark.rdd.RDD[U]

一句话概括:
对集合中每个元素进行操作,你map里面传入的方法返回的数据是U类型,map就返回个包装好的RDD[U]类型

map接口的意思是入参是传入一个方法(方法的入参是对象T,出参是对象U),然后map接口会返回一个你传入方法的返回对象U的RDD封装。即为RDD[U]。
可能这么说有点抽象,看一哈代码可能就很清晰了嗷

object mapTest {
  def main(args: Array[String]): Unit = {
    val conf = new SparkConf().setAppName("mapTest").setMaster("local")
    val sc = new SparkContext(conf)
    val data = Array("name:xiaohuangzi","age:30","profession:student")
    val lines = sc.parallelize(data,1)
    val resultRdd = lines.map(x=>x.split(":"))
    resultRdd.foreach(x=>println(x(0)+"   :    "+x(1)))
  }
}

lines的类型就是RDD[String],lines.map中,其中输入参数就是String类型,输出参数就是x.split(": ")即String[]类型,所以resultRdd 的类型就是RDD[String[]]。所以在遍历resultRdd 的时候,相当于遍历每个String[],所以我们需要用X(0),X(1)的方式来获取数据,来看一下结果。
在这里插入图片描述
如果你是在不知道返回的是啥类型,记住一句话就行,就是你传入map里的方法返回的是啥,那么map就返回什么类型的RDD,上面的例子很好的体现了哦。

2.flatMap

def flatMap[U](f : scala.Function1[T, scala.TraversableOnce[U]])(implicit evidence$4 : scala.reflect.ClassTag[U]) : org.apache.spark.rdd.RDD[U]

其中flatMap传入的方法当中,输入参数是对象T,输出参数是一个TraversableOnce[U],可以理解为对象U的集合,然后最后flatMap返回一个RDD[u]。

TraversableOnce 图如下:
在这里插入图片描述一句话概括:
对集合中每个元素进行操作返回一个集合,最后在扁平化返回一个对象。你flatMap里面传入的方法返回的数据是 集合 U类型,flatMap就将集合U类型扁平化,返回一个RDD[U]类型。比如你传入的方法返回的是List< String >/String[],那么flatMap将返回RDD[String]

然后再来看个跟map差不多的例子

object flatMapTest {
  def main(args: Array[String]): Unit = {
    val conf = new SparkConf().setAppName("mapTest").setMaster("local")
    val sc = new SparkContext(conf)
    val data = Array("name:xiaoming","age:30","profession:student")
    val lines = sc.parallelize(data,1)
    val resultRdd = lines.flatMap(x=>x.split(":"))
    resultRdd.foreach(x=>println(x))
  }
}

lines的类型就是RDD[String],lines.flatMap中,其中输入参数就是String类型,输出参数就是x.split(": ")即String[]类型,算一个集合;所以resultRdd 的类型就是RDD[String](将这个集合打平,)。所以在遍历resultRdd 的时候,相当于遍历每个String,所以我们直接用X的方式来获取数据,来看一下结果

在这里插入图片描述这个结果很显然,flatMap传入方法的返回参数是String[],所以flatMap返回的RDD[String],将String[]打平,成为一个统一的RDD[String]类型。

再来看一个非常有趣的例子:

object flatMapTest {
  def main(args: Array[String]): Unit = {
    val conf = new SparkConf().setAppName("mapTest").setMaster("local")
    val sc = new SparkContext(conf)
    val arr2=sc.parallelize(Array(("a",1),("b",2),("c",3)))
    val result2 = arr2.flatMap(x=>(x._1+x._2))
    result2.foreach(x=>println(x))
  }
}

一看到这个例子,是不是猛然觉得,这个代码能运行起来嘛,因为flatMap传入的方法返回参数不是要一个集合嘛,但是String算集合嘛?
在这里插入图片描述算的,所以运行出来的结果是
在这里插入图片描述
再来看一个例子,加深一下印象

object flatMapTest {
  def main(args: Array[String]): Unit = {
    val conf = new SparkConf().setAppName("mapTest").setMaster("local")
    val sc = new SparkContext(conf)
    val data = Array("name:xiaohuangzi","age:30","profession:student")
    val lines = sc.parallelize(data,1)
    val resultRdd = lines.flatMap(x=>x.split(":")).flatMap(x=>x)
    resultRdd.foreach(x=>print(" * "+x))
  }
}

在这里插入图片描述结果如上。其实原理跟上上个例子一样,异曲同工之妙吧。

3.mapPartitions

mapPartitions接口定义如下:

def mapPartitions[U](f : scala.Function1[scala.Iterator[T], scala.Iterator[U]], preservesPartitioning : scala.Boolean = { /* compiled code */ })(implicit evidence$6 : scala.reflect.ClassTag[U]) : org.apache.spark.rdd.RDD[U] = { /* compiled code */ }

一句话概括:mapPartitions中传入的方法输入参数是T对象的迭代器,返回对象是U对象的迭代器,最终mapPartitions返回是RDD[U],map是针对每个元素进行操作,mapPartitions是针对不同分区的数据进行操作。假设有10个元素,3个分区,你需要在map或者mapPartitions里建立数据库链接,那么map会建立10次,而mapPartitions会只建立3次链接,这就是mapPartitions的优点

接下来看个例子,就能看出有啥不同了

object mapPartitionTest {
  def main(args: Array[String]): Unit = {
    val conf = new SparkConf().setAppName("mapPartitionTest").setMaster("local")
    val sc = new SparkContext(conf)
    val a = sc.parallelize(1 to 10, 3)
    val result1 = a.map(x=>{println("map : " + x);x*2})
    val result2 = a.mapPartitions(iterator=>{println("mapPartition start");val res = for(x <- iterator) yield x*2;res} )
    println("result1 iterator :")
    result1.foreach(x=>println(x))
    println("result2 iterator :")
    result2.foreach(x=>println(x))
  }
}

在这里插入图片描述
在这里插入图片描述
所以我们可以看出,map是针对每个元素,也就是10个元素进行的;而mapPartitions则是针对我们设置的3个分区,遍历了3次。

而且我们可以发现,其实result1和result2的数据类型都是RDD[Int],并且数据都是扩大了2倍,是一样的,所以有的时候根据具体情况,map和mapPartitions是可以互换的,达到效果一样的目的,但是mapPartitions的效果比map好,要根据实际情况替换。

好了,都讲解完了,如果有错就给我留言,我好及时改正,及时进步。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值