你真知道如何高效用mapPartitions吗?

做过一段时间spark的应用开发的小伙伴都会渐渐发现,很没趣,因为都是调API。那么,真的是没趣吗,还是说你本身没有去深入研究呢?通过本文你就会发现自己没成长是哪的问题了。

浪尖会花一段时间在spark的算子原理分析和高性能使用对比方面的分析,并将这些知识放到浪尖的知识星球里。有兴趣的同学扫描底部二维码或者点击阅读原文加入星球。昨天将spark1.6源码阅读视频已经上传到星球里。

顺便打个广告,浪尖开了知乎,有兴趣的可以关注一下,搜索浪尖即可。

1. mappartition粗介

 

本问主要想讲如何高效的使用mappartition。

首先,说到mappartition大家肯定想到的是map和MapPartition的对比。网上这类教程很多了,以前浪尖也发过类似的,比如

对比foreach和foreachpartition

主要是map和foreach这类的是针对一个元素调用一次我们的函数,也即是我们的函数参数是单个元素,假如函数内部存在数据库链接、文件等的创建及关闭,那么会导致处理每个元素时创建一次链接或者句柄,导致性能底下,很多初学者犯过这种毛病。

而foreachpartition是针对每个分区调用一次我们的函数,也即是我们函数传入的参数是整个分区数据的迭代器,这样避免了创建过多的临时链接等,提升了性能。

下面的例子都是1-20这20个数字,经过map或者MapPartition然后返回a*3。

2. map栗子

val a = sc.parallelize(1 to 20, 2)

def mapTerFunc(a : Int) : Int = {    a*3}

val mapResult = a.map(mapTerFunc) 

println(mapResult.collect().mkString(","))
  结果

3,6,9,12,15,18,21,24,27,30,33,36,39,42,45,48,51,54,57,60
 

3. mappartitions低效用法

 

大家通常的做法都是申请一个迭代器buffer,将处理后的数据加入迭代器buffer,然后返回迭代器。如下面的demo。

val a = sc.parallelize(1 to 20, 2)  

def terFunc(iter: Iterator[Int]) : Iterator[Int] = {   

 var res = List[Int]()    

while (iter.hasNext)    {     

 val cur = iter.next;      

res.::= (cur*3) ;    

}    

res.iterator  

}

val result = a.mapPartitions(terFunc) 

println(result.collect().mkString(","))

 

结果

30,27,24,21,18,15,12,9,6,3,60,57,54,51,48,45,42,39,36,33
 

4. mappartitions高效用法

注意,3中的例子,会在mappartition执行期间,在内存中定义一个数组并且将缓存所有的数据。假如数据集比较大,内存不足,会导致内存溢出,任务失败。 对于这样的案例,Spark的RDD不支持像mapreduce那些有上下文的写方法。其实,浪尖有个方法是无需缓存数据的,那就是自定义一个迭代器类。如下例:

class CustomIterator(iter: Iterator[Int]) extends Iterator[Int] {   

def hasNext : Boolean = {     
     iter.hasNext    
 }    
def next : Int= {        

    val cur = iter.next        
    cur*3    
}  
}    

val result = a.mapPartitions(
v => new CustomIterator(v)
)  

println(result.collect().mkString(","))

结果:

3,6,9,12,15,18,21,24,27,30,33,36,39,42,45,48,51,54,57,60

是不是脑洞大开,要多学习的,同志们。

【完】

  • 2
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 8
    评论
在Java中使用Spark SQL的mapPartitions方法,可以按照如下方式进行: 1. 首先,你需要创建一个JavaSparkContext对象和SQLContext对象。这两个对象的创建方式如下: ```java SparkConf conf = new SparkConf().setAppName("MapPartitionsExample").setMaster("local[*]"); JavaSparkContext sc = new JavaSparkContext(conf); SQLContext sqlContext = new SQLContext(sc); ``` 2. 接下来,你需要创建一个JavaRDD对象。在这个例子中,我们创建一个包含四个元素的JavaRDD,每个元素都是一个字符串: ```java JavaRDD<String> rdd = sc.parallelize(Arrays.asList("apple", "banana", "cherry", "date"), 2); ``` 3. 然后,你需要定义一个函数,该函数将应用于每个分区。在这个例子中,我们定义了一个函数,该函数将返回一个包含每个元素的长度的列表: ```java Function<Iterator<String>, Iterator<Integer>> mapPartitionsFunc = new Function<Iterator<String>, Iterator<Integer>>() { @Override public Iterator<Integer> call(Iterator<String> iterator) throws Exception { ArrayList<Integer> list = new ArrayList<Integer>(); while (iterator.hasNext()) { String s = iterator.next(); list.add(s.length()); } return list.iterator(); } }; ``` 4. 最后,我们将mapPartitions函数应用于JavaRDD对象,并收集结果: ```java JavaRDD<Integer> result = rdd.mapPartitions(mapPartitionsFunc); List<Integer> resultList = result.collect(); for (Integer i : resultList) { System.out.println(i); } ``` 完整的Java代码如下: ```java import org.apache.spark.SparkConf; import org.apache.spark.api.java.JavaRDD; import org.apache.spark.api.java.JavaSparkContext; import org.apache.spark.api.java.function.Function; import org.apache.spark.sql.SQLContext; import java.util.ArrayList; import java.util.Arrays; import java.util.Iterator; import java.util.List; public class MapPartitionsExample { public static void main(String[] args) { SparkConf conf = new SparkConf().setAppName("MapPartitionsExample").setMaster("local[*]"); JavaSparkContext sc = new JavaSparkContext(conf); SQLContext sqlContext = new SQLContext(sc); JavaRDD<String> rdd = sc.parallelize(Arrays.asList("apple", "banana", "cherry", "date"), 2); Function<Iterator<String>, Iterator<Integer>> mapPartitionsFunc = new Function<Iterator<String>, Iterator<Integer>>() { @Override public Iterator<Integer> call(Iterator<String> iterator) throws Exception { ArrayList<Integer> list = new ArrayList<Integer>(); while (iterator.hasNext()) { String s = iterator.next(); list.add(s.length()); } return list.iterator(); } }; JavaRDD<Integer> result = rdd.mapPartitions(mapPartitionsFunc); List<Integer> resultList = result.collect(); for (Integer i : resultList) { System.out.println(i); } } } ``` 在这个例子中,我们使用mapPartitions方法将每个元素转换成一个整数,然后将结果打印到控制台。
评论 8
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值