将对象副本传递给hadoop中所有映射器的最佳实践

时间:2012-11-21 20:10:38

标签: java hadoop mapreduce

您好我正在学习Map Reduce,我正在尝试使用hadoop 1.0.4构建一个小作业。我有一个停用词列表和一个模式列表。在我的文件映射之前,我想在一个有效的数据结构(如地图)中加载stoppwords。我还想从我的模式列表中构建一个正则表达式模式。由于这些是串行任务,我想在映射前执行​​它们,并将每个映射器的副本传递给它们可以读/写的对象。我想过在我的驱动程序类中只有一个带有getter的静态变量,但是使用java调用对象作为指针原则这不起作用。我当然可以在传递之前克隆对象,但这似乎不是一个好习惯。我读了一些关于分布式缓存的东西,但据我所知,它仅用于文件而不是用于对象,而且我可以让每个映射器读取stopp word / pattern文件。

感谢您的帮助!

2 个答案:

答案 0 :(得分:2)

一种可能的解决方案是在运行作业之前将stopwords.txt复制到HDFS, 然后在Mapper的setup方法中将其读入适当的数据结构。 E.g:

MyMapper类:

...
private Map<String, Object> stopwords = null;

@Override
public void setup(Context context) {
    Configuration conf = context.getConfiguration();
    //hardcoded or set it in the jobrunner class and retrieve via this key
    String location = conf.get("job.stopwords.path");
    if (location != null) {
        BufferedReader br = null;
        try {
            FileSystem fs = FileSystem.get(conf);
            Path path = new Path(location);
            if (fs.exists(path)) {
                stopwords = new HashMap<String, Object>();
                FSDataInputStream fis = fs.open(path);
                br = new BufferedReader(new InputStreamReader(fis));
                String line = null;
                while ((line = br.readLine()) != null && line.trim().length() > 0) {
                    stopwords.put(line, null);
                }
            }
        }
        catch (IOException e) {
            //handle
        } 
        finally {
            IOUtils.closeQuietly(br);
        }
    }
}
...

然后您可以在地图方法中使用停用词

另一种选择是在jobrunner类中使用停用词创建地图对象, 将其序列化为Base64编码的String,将其作为Configuration对象中某个键的值传递给映射器,并在setup方法中对其进行反序列化。

我会选择第一个选项,不仅因为它更容易,而且因为通过Configuration对象传递更大量的数据不是一个好主意。

答案 1 :(得分:2)

Hadoop分布式缓存是一种特定的机制,可以将一些引用数据传递给映射器。从性能角度来看,最好从HDFS加载 - 因为数据将从每个节点一次从HDFS传递到本地文件系统,而不是每个任务一次。
你完全正确 - 它只适用于文件和阅读文件并将它们转换为你的数据结构是你的责任。
据我所知,hadoop不支持传递对象。虽然如果您在这些文件中使用某种序列化 - 它将接近您的要求。