在MapReduce中,Mapper和Reducer可以声明一个setup方法,在处理一个split输入之前执行,来进行分配数据库连接等昂贵资源,同时可以用cleanup函数可以释放资源。
public class SetupCleanupMapper extends
Mapper<LongWritable, Text, Text, IntWritable> {
private Connection dbConnection;
@Override
protected void setup(Context context) {
dbConnection = ...;
}
...
@Override
protected void cleanup(Context context) {
dbConnection.close();
}
}
Spark中的map和flatMap等方法每次只能在一个input(一行)上操作,而且没有提供在转换大批值前后执行代码的方法。
但是可以用mapPartitions或mapPartitionsToPair方法来实现类似setup的目的。
mapPartitions方法和map方法类似,只不过映射函数的参数由RDD中的每一个元素变成了RDD中每一个分区的迭代器。如果在映射的过程中需要频繁创建额外的对象,使用mapPartitions要比map高效的过。
比如,将RDD中的所有数据通过JDBC连接写入数据库,如果使用map函数,可能要为每一个元素都创建一个connection,这样开销很大,如果使用mapPartitions,那么只需要针对每一个分区建立一个connection。
JavaRDD<Integer> mapOrder = sc.textFile(logFile,3).map(new Function<String,Integer>(){//读取文本,分成3个分区
public Integer call(String v1) throws Exception {
// TODO Auto-generated method stub
return Integer.parseInt(v1);
}
});
TTLPartition ttl=new TTLPartition();
// ttl.setup();
JavaPairRDD<Integer, String> res1Pair=
mapOrder.mapPartitionsToPair( ttl).partitionBy(new HashPartitioner(1)).//ttl对象是你要处理数据的逻辑
reduceByKey(new Function2<String,String,String>(){
public String call(String v1, String v2) throws Exception {
// TODO Auto-generated method stub
return v1+v2;
}}).sortByKey();
mapPartitionsToPair的call方法实现如下:
public Iterator<Tuple2<Integer, String>> call(Iterator<Integer> t) throws Exception {
// TODO Auto-generated method stub
setup();//这样就实现mapreduce中对每一个split做预处理,之后才是该split中每一个数据的处理逻辑:迭代器t遍历split,每个数据运行一次map方法
int vi=0;
while(t.hasNext())
{
vi=t.next();
map(vi);
}
cleanup();