使用MapReduce中的globStatus过滤输入文件

时间:2013-01-15 06:36:31

标签: java hadoop mapreduce cloudera

我有很多输入文件,我想根据最后附加的日期处理选定的文件。我现在很困惑我在哪里使用globStatus方法来过滤掉文件。

我有一个自定义的RecordReader类,我试图在下一个方法中使用globStatus,但它没有用完。

public boolean next(Text key, Text value) throws IOException {
    Path filePath = fileSplit.getPath();

    if (!processed) {
        key.set(filePath.getName());

        byte[] contents = new byte[(int) fileSplit.getLength()];
        value.clear();
        FileSystem fs = filePath.getFileSystem(conf);
        fs.globStatus(new Path("/*" + date));
        FSDataInputStream in = null;

        try {
            in = fs.open(filePath);
            IOUtils.readFully(in, contents, 0, contents.length);
            value.set(contents, 0, contents.length);
        } finally {
            IOUtils.closeStream(in);
        }
        processed = true;
        return true;
    }
    return false;
}

我知道它会返回一个FileStatus数组,但是如何使用它来过滤文件。有人可以解释一下吗?

2 个答案:

答案 0 :(得分:10)

globStatus方法需要2个免费参数,允许您过滤文件。第一个是glob模式,但有时glob模式不足以过滤特定文件,在这种情况下,您可以定义PathFilter

关于glob模式,支持以下内容:

Glob   | Matches
-------------------------------------------------------------------------------------------------------------------
*      | Matches zero or more characters
?      | Matches a single character
[ab]   | Matches a single character in the set {a, b}
[^ab]  | Matches a single character not in the set {a, b}
[a-b]  | Matches a single character in the range [a, b] where a is lexicographically less than or equal to b
[^a-b] | Matches a single character not in the range [a, b] where a is lexicographically less than or equal to b
{a,b}  | Matches either expression a or b
\c     | Matches character c when it is a metacharacter

PathFilter只是这样的界面:

public interface PathFilter {
    boolean accept(Path path);
}

因此,您可以实现此接口并实现accept方法,您可以将逻辑用于过滤文件。

Tom White's excellent book获取的示例,它允许您定义PathFilter以过滤与特定正则表达式匹配的文件:

public class RegexExcludePathFilter implements PathFilter {
    private final String regex;

    public RegexExcludePathFilter(String regex) {
        this.regex = regex;
    }

    public boolean accept(Path path) {
        return !path.toString().matches(regex);
    }
}

您可以在初始化作业时致电PathFilter,通过FileInputFormat.setInputPathFilter(JobConf, RegexExcludePathFilter.class)实施直接过滤输入。

编辑:由于您必须在setInputPathFilter中传递该类,因此无法直接传递参数,但您应该可以通过使用{{1}来执行类似操作}}。如果您使Configuration也从[{1}}延伸,您可以使用所需的值恢复之前已初始化的RegexExcludePathFilter对象,这样您就可以在过滤器中找回这些值并在Configured

中处理它们

例如,如果你这样初始化:

Configuration

然后您可以像这样定义过滤器:

accept

编辑2 :原始代码存在一些问题,请参阅更新后的课程。您还需要删除构造函数,因为它不再使用,并检查这是否是一个目录,在这种情况下您应该返回true,这样也可以过滤目录的内容。

答案 1 :(得分:2)

对于阅读此内容的任何人,我是否可以说“请不要在过滤器中做任何比验证路径更复杂的事情”。具体来说:不要检查作为目录的文件,获取它们的大小等。等待列表/ glob操作返回,然后使用填充的FileStatus条目中的信息在那里进行过滤。

为什么呢?所有这些直接或通过getFileStatus()isDirectory()的调用正在对文件系统进行不必要的调用,这些调用会在HDFS集群上添加不必要的namenode负载。更重要的是,针对S3和其他对象存储,每个操作都可能发出多个HTTPS请求 - 而这些确实需要花费大量时间。更好的是,如果S3认为您在整个机器群集中发出过多请求,S3会限制您。你不希望这样。

直到调用之后 - 你得到的文件状态条目是来自对象存储列表命令的那些,通常每个HTTPS请求返回数千个文件条目,因此效率更高。

有关详细信息,请查看org.apache.hadoop.fs.s3a.S3AFileSystem

的来源