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
在我的情况下,目录存储
Avro
不同类型数据的模式
(本例中为A、B和C)
在不同的日期。架构可能会开始现有、发展并停止现有。。。随着时间的流逝。
球门
我需要能够尽快获取给定类型的所有模式。在我希望获取类型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
但在某种程度上由客户处理。我似乎找不到合适的源代码来查看它是如何实现的。
以下是我的第一张照片,可能有点太天真了。。。
使用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());
}
结果:
感谢
PathFilter
s和数组的使用,它的性能似乎更快
12秒
). 然而,代码更复杂,更难以适应不同的情况。最重要的是,性能仍然比命令行版本慢3到4倍!
问题
我在这里缺少什么?获得我想要的结果的最快方法是什么?
更新
2014.07.09 - 13:38
拟议的
answer
属于
Mukesh S
显然是最好的API方法。
在我上面给出的示例中,代码看起来像这样:
FileStatus[] statuses = filesystem.globStatus(new Path("/schemas_folder/date=*/A-schema.avsc"));
for (FileStatus status : statuses)
{
System.out.println(status.getPath());
}
这是迄今为止我能想到的最漂亮、性能最好的代码,但性能仍然不如shell版本。