上面这个方法有一个限制:
conf.set()方法只能传递String类型的变量,如果在mapper或reducer中更合适使用别的类型(比如List,Map等),则需要通过一些方法来转换,而如果转换方法比较复杂或者数据量比较大,则对整个程序的效率会产生很大的影响,因为上面这种方法每次调用map函数都会进行同样的转换,这种重复性的工作是不可容忍的,并且也违反了我们使用全局变量的初衷。
替代的方法是将static变量定义为mapper类的成员变量,并在static块或static成员函数中进行初始化,这样整个mapper过程只需对static变量初始化一次,这对效率会有很大的提高。
程序结构如下:
public class myMR{
public static class myMapper extends Mapper<Text, Text, Text, Text>{
private static Set<**> subglobal;
//other static variable
static{
//initialize 'subglobal'
}
//other static blocks
public void map(Text key, Text value, Context context)
throws IOException, InterruptedException{
//直接使用subglobal
}
}
public static class myReducer extends Reducer<Text, Text, Text, Text>{
public void reducer(Text key, Iterable<Text>, Context context)
throws IOException, InterruptedException{
//reducer process
}
}
public static void main(String[] args){
//your job
}
对java熟悉的话很容易就可以看出来,这只是个static对象初始化问题。但是这种方法使用的并不是mapper和reducer角度上的全局变量,而只是站在某个mapper task角度上的“全局变量”。而这种情况下除了使用static变量及其初始化块这种方法之外,还可以添加自定义的setup(Context)和close(Context)函数来初始化,这两个方法只在某mapper或reducer task开始和结束的时候分别调用一次,可以起到与上面代码所用方法一样的效果。
|