设为首页 加入收藏

TOP

Hadoop环境编程-Configuration类的使用
2019-02-09 00:44:11 】 浏览:19
Tags:Hadoop 环境 编程 -Configuration 使用

程序开发中,经常需要将程序执行中的相关参数进行可配置化,以实现程序的灵活性。在Hadoop环境下编程,也有同样的需求。本文介绍在MapReduce编程中,怎样使用Configuration类读取相关配置。这些配置可能不仅仅在Job配置时需要,有些配置还要在Map或者Reduce编程间传递。

一.读取配置
在以往的编程中,通常将相关参数预先写入相关文件中(如xml,json,Java中的properties,C++中libconfig等),然后在程序初始化时读取该配置项,存入特定的变量中,这种操作在MapReduce中是否可行了?除此之外,是否还有其他方法了?
首先,介绍以往编程中常用的方法,即将配置读取解析后存在一个Singleton对象中,实际运行中会发现这种方法存在局限性。其次,介绍使用Hadoop提供的Configuration类来存取配置项。

代码结构:

//JobConf.java
package com.test.hadoop.conf;

public class JobConf {

    private int nAge;
    private String strName;

    private static JobConf instance = null;

    private JobConf(){  
    }

    public static JobConf Instance(){
        if(instance != null){
            return instance;
        }
        synchronized (JobConf.class) {
            if(instance != null){
                return instance;
            }
            instance = new JobConf();
        }
        return instance;
    }

    public void setAge(int age){
        this.nAge = age;
    }

    public void setName(String name){
        this.strName = name;
    }

    public int getAge(){
        return this.nAge;
    }

    public String getName(){
        return this.strName;
    }
}
//JobTask.java
package com.test.hadoop.conf;

import java.io.IOException;
...
public class JobTask {

    private static final Log mLogger = LogFactory.getLog(JobTask.class);
    private String MR_NAME = "wordcount";

    public boolean execute() throws IOException, ClassNotFoundException, InterruptedException{
        Configuration conf = new Configuration();

        mLogger.info("JobTask Age:" + JobConf.Instance().getAge() + ", Name:" + JobConf.Instance().getName());

        //method 1
        conf.addResource("test.xml");
        mLogger.info("JobTask flower:" + conf.get("flower")+",color:"+conf.get("color"));
        //method 2
        conf.set("code.language", "java");
        conf.set("compute.method", "mapreduce");
        mLogger.info("JobTask language:" + conf.get("code.language")+",method:"+conf.get("compute.method"));

        Job job = Job.getInstance(conf, MR_NAME);
        ...      
        boolean success = job.waitForCompletion(true);
        ...
        return true;
    }

    public static void main(String[] args) {
        JobTask job = new JobTask();    
        //bad case
        JobConf.Instance().setAge(20);
        JobConf.Instance().setName("Coder9527");

        try {
            if(job.execute()){
                mLogger.info(" run success");
            }
        } catch (Exception e) {
            mLogger.error(e);
        }
    }
}
//JobMap.java
package com.test.hadoop.conf;

import java.io.IOException;
...

public class JobMap extends Mapper<Object, Text, Text, IntWritable>{

    private static final Log mLogger = LogFactory.getLog(JobTask.class);
    ...
    protected void setup(Context context){
        //bad case
       mLogger.info("JobMap Age:" + JobConf.Instance().getAge() + ", Name:" + JobConf.Instance().getName());
       //well case
       mLogger.info("JobMap flower:" + context.getConfiguration().get("flower")+",color:"+context.getConfiguration().get("color"));
       mLogger.info("JobMap language:" + context.getConfiguration().get("code.language")+",method:"+context.getConfiguration().get("compute.method"));
    }

    public void map(Object key, Text value, Context context) throws IOException, InterruptedException {
        ...
    }   
}
//JobReduce.java
package com.test.hadoop.conf;

import java.io.IOException;
...

public class JobReduce extends Reducer<Text,IntWritable,Text,IntWritable>{

    private static final Log mLogger = LogFactory.getLog(JobTask.class);
    ...

    protected void setup(Context context){
        //bad case
        mLogger.info("JobReduce Age:" + JobConf.Instance().getAge() + ", Name:" + JobConf.Instance().getName());
        //well case 
        mLogger.info("JobReduce flower:" + context.getConfiguration().get("flower")+",color:"+context.getConfiguration().get("color"));
        mLogger.info("JobReduce language:" + context.getConfiguration().get("code.language")+",method:"+context.getConfiguration().get("compute.method"));
    }
    public void reduce(Text key, Iterable<IntWritable> values,Context context ) throws IOException, InterruptedException {
        ...
    }
}
//test.xml
<configuration>
    <property>
        <name>flower</name>
        <value>rose</value>
        <description>flower name</description>
    </property>

    <property>
        <name>color</name>
        <value>red</value>
        <final>true</final>
        <description>flower color,final value,unmodified</description>
    </property>
</configuration>

在上述的代码中,以wordcount为例,介绍怎样读取参数,并将参数传递到map和reduce编程中,此处旨在介绍参数的读取等,M/R计算的相关代码在此略过,读者可以参考Hadoop MapReduce-wordcount示例
JobConf类是一个Singleton,用于保存相关的参数,并且我们期望在其他的类中可以读取到相关参数。main()方法中通过JobTask实例提供的set方法模拟参数的读取。在其他方法中试图通过Singleton提供的get方法获取到该参数。如下:

JobConf.Instance().setAge(20);
JobConf.Instance().getAge();

Configuration类是由Hadoop提供的,通过addResource()方法读取满足特定格式xml文件来读取相关的配置项,读取后的配置项会保存到M/R程序执行的上下文环境中,可以通过Configuration类的get方法获取,也可以在Context对象中获取。

Configuration conf = new Configuration();
conf.addResource("test.xml");
conf.get("flower"); //通过Configuration类的get方法获取
context.getConfiguration().get("flower"); //通过Context对象获取

Configuration类还提供了set方法,直接配置key-value形式的参数,配置后参数同样可以通过get方法和Context对象获取。
那么上述代码的执行结果了?
JobTask中输出:

... INFO conf.JobTask: JobTask Age:20, Name:Coder9527
... INFO conf.JobTask: JobTask flower:rose,color:red
... INFO conf.JobTask: JobTask language:java,method:mapreduce

JobMap中输出:

... INFO [main] com.test.hadoop.conf.JobTask: JobMap Age:0, Name:null
... INFO [main] com.test.hadoop.conf.JobTask: JobMap flower:rose,color:red
... INFO [main] com.test.hadoop.conf.JobTask: JobMap language:java,method:mapreduce

JobReduce中输出:

... INFO [main] com.test.hadoop.conf.JobTask: JobReduce Age:0, Name:null
... INFO [main] com.test.hadoop.conf.JobTask: JobReduce flower:rose,color:red
... INFO [main] com.test.hadoop.conf.JobTask: JobReduce language:java,method:mapreduce

运行结果表明,单例JobConf的结果只能在JobTask中可以获取,而在其他类中没法获取,是一个空指针。事实上在作业提交后,application master就会为该作业所有的map任务和reduce任务向资源管理器请求容器(容器:YARN为资源隔离而提出的框架),每个任务对应一个容器,且只能在该容器中执行。此外在任务执行前将资源本地化,即通过共享文件系统拷贝作业的配置,jar文件和所有来自分布式缓存的文件。由于资源隔离,map任务和reduce任务无法共享task中JobConf之前的set设置。

二、Configuration
通过上面的介绍,在Hadoop环境下的编程更应该使用Configuration类来设置和获取相关配置。下面对于Configuration类进行介绍。
1.Configuration类的配置文件

<configuration>
    <property>
        <name>flower</name>
        <value>rose</value>
        <description>flower name</description>
    </property>

    <property>
        <name>color</name>
        <value>red</value>
        <final>true</final>
        <description>flower color,final value,unmodified</description>
    </property>

    <property>
        <name>descript</name>
        <value>The color of ${flower} is red</value>
        <description>flower color,final value,unmodified</description>
    </property>
</configuration>

每个property代表一个配置项,其由属性名称、属性值以及描述定义组成。需要注意的是属性color多了一个final定义,表示此属性不能被覆盖,在第三个属性descript中,其value值被定义为含有可拓展的变量${flower}。
Configuration类addResource方法有多个重载类型,其中addResource(String name),加载的xml文件的路径为{HADOOP_HOME}/etc/hadoop,也就是需要将test.xml放置在此目录下才能读取。如果想加载指定路径下的xml文件配置可以使用addResource(Path file)方法。
下面的代码演示了final定义的作用。

//test.xml
<configuration>
    <property>
        <name>flower</name>
        <value>rose</value>
        <description>flower name</description>
    </property>

    <property>
        <name>color</name>
        <value>red</value>
        <final>true</final>
        <description>flower color,final value,unmodified</description>
    </property>
</configuration>
//test2.xml
<configuration>
    <property>
        <name>flower</name>
        <value>viole</value>
        <description>flower name</description>
    </property>

    <property>
        <name>color</name>
        <value>violet</value>
        <final>true</final>
        <description>flower color,final value,unmodified</description>
    </property>
</configuration>
package com.test.hadoop.conf;

import org.apache.hadoop.conf.Configuration;

public class Test {

    public static void main(String[] args) {
        Configuration conf = new Configuration();
        conf.addResource("test.xml");
        System.out.println("flower:" + conf.get("flower")+",color:"+conf.get("color"));
        conf.addResource("test2.xml");
        System.out.println("flower:" + conf.get("flower")+",color:"+conf.get("color"));
    }

}

程序输出:

flower:rose,color:red
17/10/12 17:52:58 WARN conf.Configuration: test2.xml:an attempt to override final parameter: color;  Ignoring.
flower:viole,color:red

2.属性的覆盖
前面提及Configuraion允许你通过两种方式设置key/value格式的属性,一种是通过set方法,另一种通过addResouce(String name),将一个xml文件加载到Configuration中。那么下面的情况说输出什么

Configuration conf = new Configuration();
conf.set("flower","viole");
conf.addResource("test.xml"); //flower->rose
System.out.println("flower:" + conf.get("flower"));

其结果是输出”viole”,也就是说”rose”值无法覆盖原来的”viole”。因为当一个配置属性是用户通过set方法设置的时,该属性的来源将被标注为“programatically”,这样的属性是不能被addResource方法覆盖的,必须通过set方法覆盖或修改。事实上在addResource实现中,首先会用指定的xml文件覆盖包含的所有属性,之后再还原“programmatically”来源的那些属性。


编程开发网
】【打印繁体】【投稿】【收藏】 【推荐】【举报】【评论】 【关闭】 【返回顶部
上一篇Hadoop心得 下一篇Hadoop:分布式计算平台初探

评论

帐  号: 密码: (新用户注册)
验 证 码:
表  情:
内  容:

array(4) { ["type"]=> int(8) ["message"]=> string(24) "Undefined variable: jobs" ["file"]=> string(32) "/mnt/wp/cppentry/do/bencandy.php" ["line"]=> int(214) }