java – 通用卡在Hadoop的FileSystem中列出API调用

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命令,似乎在Java API中似乎找不到与上面的命令相同的命令.当我尝试自己实施循环,我会得到可怕的表现.我至少要命令行的表现(在我的情况下约3秒)…

到目前为止我发现了

可以注意到,它打印两次发现1个项目,每次结果之前一次.它一开始就不打印找到2个项目.这可能暗示通配符在FileSystem方面未实现,但由客户端处理.我似乎找不到正确的源代码来看看它是如何实现的.

下面是我的第一枪,可能有点太天真了…

使用listFiles(…)

码:

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());
}

结果:

由于PathFilters和数组的使用,它似乎执行得更快(约12秒).然而,代码更复杂,并且更难适应不同的情况.最重要的是,性能比命令行版本慢3到4倍!

我在这里缺少什么?什么是最快的方式来获得我想要的结果?

更新

2014.07.09 – 13:38

Mukesh S提出的answer显然是最好的API方法.

在上面给出的例子中,代码最终如下所示:

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

这是迄今为止所能找到的最好看的和最好的代码,但是仍然不能像shell一样执行.

解决方法

而不是listStatus,您可以尝试hadoops globStatus. Hadoop提供了两种用于处理globs的FileSystem方法
public FileStatus[] globStatus(Path pathPattern) throws IOException
public FileStatus[] globStatus(Path pathPattern,PathFilter filter) throws IOException

可以指定一个可选的PathFilter来进一步限制匹配.

有关更多说明,您可以检查Hadoop:最终指南here

希望它有帮助.. !!!

相关文章

ArrayList简介:ArrayList 的底层是数组队列,相当于动态数组。与 Java 中的数组相比,它的容量能动态增...
一、进程与线程 进程:是代码在数据集合上的一次运行活动,是系统进行资源分配和调度的基本单位。 线程...
本文为博客园作者所写:&#160;一寸HUI,个人博客地址:https://www.cnblogs.com/zsql/ 简单的一个类...
#############java面向对象详解#############1、面向对象基本概念2、类与对象3、类和对象的定义格式4、...
一、什么是异常? 异常就是有异于常态,和正常情况不一样,有错误出错。在java中,阻止当前方法或作用域...
Collection接口 Collection接口 Collection接口 Collection是最基本的集合接口,一个Collection代表一组...