java—hadoop文件系统中列出api调用的通配符

iugsix8n  于 2021-06-03  发布在  Hadoop
关注(0)|答案(1)|浏览(388)

tl;dr: 要在列出的路径中使用通配符(globs),只需使用 globStatus(...) 而不是 listStatus(...) .

上下文

我的hdfs集群上的文件是按分区组织的,日期是“根”分区。文件结构的简化示例如下所示:

/schemas_folder
├── date=20140101
│   ├── A-schema.avsc
│   ├── B-schema.avsc
├── date=20140102
│   ├── A-schema.avsc
│   ├── B-schema.avsc
│   ├── C-schema.avsc
└── date=20140103
    ├── B-schema.avsc
    └── C-schema.avsc

在我的例子中,目录在不同的日期为不同类型的数据(本例中为a、b和c)存储avro模式。架构可能开始存在,演变和停止存在。。。随着时间的推移。

目标

我需要能够尽快获得给定类型的所有模式。在这个示例中,我想获取类型a的所有模式,我想执行以下操作:

hdfs dfs -ls /schemas_folder/date=*/A-schema.avsc

那会给我

Found 1 items
-rw-r--r--   3 user group 1234 2014-01-01 12:34 /schemas_folder/date=20140101/A-schema.avsc
Found 1 items
-rw-r--r--   3 user group 2345 2014-01-02 23:45 /schemas_folder/date=20140102/A-schema.avsc

问题

我不想使用shell命令,而且在javaapi中似乎找不到与上述命令等效的命令。当我尝试自己实现循环时,我得到了糟糕的性能。我至少想要命令行的性能(在我的情况下大约是3秒)。。。

到目前为止我发现了什么

可以注意到它打印了两次 Found 1 items ,每次结果前一次。它不打印 Found 2 items 一开始只有一次。这可能暗示了通配符没有在 FileSystem 但却被客户处理了。我似乎找不到合适的源代码来查看它是如何实现的。
下面是我的第一张照片,可能有点太天真了ï我。。。

使用列表文件(…)

代码:

RemoteIterator<LocatedFileStatus> files = filesystem.listFiles(new Path("/schemas_folder"), true);
Pattern pattern = Pattern.compile("^.*/date=[0-9]{8}/A-schema\\.avsc$");
while (files.hasNext()) {
    Path path = files.next().getPath();
    if (pattern.matcher(path.toString()).matches())
    {
        System.out.println(path);
    }
}

结果:

这完全符合我的期望,但是由于它首先递归地列出所有内容,然后过滤,所以性能非常差。在我当前的数据集中,几乎需要25秒。。。

正在使用liststatus(…)

代码:

FileStatus[] statuses = filesystem.listStatus(new Path("/schemas_folder"), new PathFilter()
{
    private final Pattern pattern = Pattern.compile("^date=[0-9]{8}$");

    @Override
    public boolean accept(Path path)
    {
        return pattern.matcher(path.getName()).matches();
    }
});
Path[] paths = new Path[statuses.length];
for (int i = 0; i < statuses.length; i++) { paths[i] = statuses[i].getPath(); }
statuses = filesystem.listStatus(paths, new PathFilter()
{
    @Override
    public boolean accept(Path path)
    {
        return "A-schema.avsc".equals(path.getName());
    }
});
for (FileStatus status : statuses)
{
    System.out.println(status.getPath());
}

结果:

多亏了 PathFilter 而且使用数组,它的性能似乎更快(大约12秒)。不过,代码更复杂,更难适应不同的情况。最重要的是,性能仍然比命令行版本慢3到4倍!

问题

我错过了什么?得到我想要的结果最快的方法是什么?

更新

2014.07.09 - 13:38

mukesh提出的答案显然是最好的api方法。
在我上面给出的示例中,代码最终如下所示:

FileStatus[] statuses = filesystem.globStatus(new Path("/schemas_folder/date=*/A-schema.avsc"));
for (FileStatus status : statuses)
{
    System.out.println(status.getPath());
}

这是迄今为止我能想到的最漂亮、性能最好的代码,但它的性能仍然不如shell版本。

2hh7jdfx

2hh7jdfx1#

您可以尝试hadoops globstatus而不是liststatus。hadoop提供了两种文件系统方法来处理glob:

public FileStatus[] globStatus(Path pathPattern) throws IOException
public FileStatus[] globStatus(Path pathPattern, PathFilter filter) throws IOException

可以指定可选的pathfilter来进一步限制匹配。
有关更多说明,请查看hadoop:definitive guide 在这里
希望对你有帮助。。!!!

相关问题