经常会有这样的需求:
在MR程序中,map,reduce等方法中需要传入一些外部参数,比如我们要编写MR程序访问页面访问的Top n,其中的n就是我们需要传入的外部参数。但是,map和reduce等方法都是由MapTask和RedcueTask调用的,我们编程的时候是从父类继承方法,然后override来实现我们的逻辑。所以方法的标签是不能改变的,那么,这个外部参数又该用怎样的方式传递给这些方法呢?
那就是利用方法的一个参数,context来传递。
先来看下这个,
Configuration conf = new Configuration(); conf.setInt("topn", 6); Job job = Job.getInstance(conf);
这是我们编写job提交程序时的一般做法,这句话的含义是创建conf对象,对job运行时的一些参数进行配置,把该conf对象封装到job对象中,job运行的时候就会去读conf中的配置信息,conf对象可以通过Context对象获取。这样反过来我们就可以为map和reduce等方法获得外部参数啦:map方法的形参包括context对象,方法执行时通过MapTask传入该参数值,然后通过context对象我们可以获取job的conf对象,如果在conf中封装了我们要传入的外部参数,那么就可以反向获得这个参数了。
在map或reduce方法中,通过以下方法可以得到配置参数值:
Configuration conf = context.getConfiguration();
int topn = conf.getInt(conf.get("topn", 5));//“topn”为要获取的参数的name,5为该参数的默认值
这里通过context获得的conf对象,是我们项目运行的通用配置信息(其实它的作用大致相当于我们在进行集群配置时修改的core-site.xml和hdfs.xml)。那么我们又该如何把topn的值放到conf对象里去呢?
在jobsubmitter中,conf对象创建后,通过set方法封装参数值。
Configuration conf = new Configuration(); conf.setInt("topn", 6);
补充:
其实,这里也是把参数值写死到代码中,那么我们怎么不把这个参数在代码中写死呢?比如我开始想求top5,现在想求top3。
方法一:利用main方法在运行时传入参数。
public class PageCountJobSubmitter { public static void main(String[] args) throws IOException, ClassNotFoundException, InterruptedException { Configuration conf = new Configuration(); conf.setInt("topn", args[0]); Job job = Job.getInstance(conf); …… } }
方法二:通过属性配置文件获取参数
public class PageCountJobSubmitter { public static void main(String[] args) throws IOException, ClassNotFoundException, InterruptedException { Configuration conf = new Configuration(); Properties properties = new Properties(); properties.load(PageCountJobSubmitter.class.getClassLoader(). getResourceAsStream("I:\CodePractice\flowcount\Topn\src\main\resources\topn.proterpties")); conf.setInt("topn", Integer.parseInt(properties.getProperty("topn"))); …… } }
方法三:通过classpath下的xml文件加载
public class PageCountJobSubmitter { public static void main(String[] args) throws IOException, ClassNotFoundException, InterruptedException { Configuration conf = new Configuration(); /* Properties properties = new Properties(); properties.load(PageCountJobSubmitter.class.getClassLoader(). getResourceAsStream("topn.proterpties")); conf.setInt("topn", Integer.parseInt(properties.getProperty("topn"))); */ conf.addResource(new Path("I:\CodePractice\" + "flowcount\Topn\src\main\java\topn.xml"));//这种绝对路径不太优雅。。。 } }
context里存储项目运行的上下文参数,
方法一:
方法二:
方法三: