sno*_*e92 15 java hadoop wildcard hdfs
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
Run Code Online (Sandbox Code Playgroud)
就我而言,该目录在不同日期存储不同类型数据(本例中为A,B和C)的Avro模式.随着时间的推移,模式可能会开始存在,发展并停止存在.
我需要能够尽快获得给定类型的所有模式.在我希望得到类型A存在的所有模式的示例中,我想执行以下操作:
hdfs dfs -ls /schemas_folder/date=*/A-schema.avsc
Run Code Online (Sandbox Code Playgroud)
那会给我
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
Run Code Online (Sandbox Code Playgroud)
我不想使用shell命令,似乎无法在Java API中找到与上面的命令等效的东西.当我尝试自己实现循环时,我的表现非常糟糕.我至少想要命令行的性能(在我的情况下大约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);
}
}
Run Code Online (Sandbox Code Playgroud)
这打印完全符合我的预期,但由于它首先以递归方式列出所有内容然后过滤,因此性能非常差.使用我当前的数据集,大约需要25秒 ......
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());
}
Run Code Online (Sandbox Code Playgroud)
由于PathFilters和数组的使用,它似乎执行得更快(大约12秒).但是代码更复杂,更难以适应不同的情况.最重要的是,性能仍然比命令行版本慢3到4倍!
我在这里错过了什么?获得我想要的结果的最快方法是什么?
在我上面给出的示例中,代码最终看起来像这样:
FileStatus[] statuses = filesystem.globStatus(new Path("/schemas_folder/date=*/A-schema.avsc"));
for (FileStatus status : statuses)
{
System.out.println(status.getPath());
}
Run Code Online (Sandbox Code Playgroud)
这是迄今为止我能想出的最佳外观且性能最佳的代码,但仍然不如shell版本那么好.
Muk*_*h S 27
您可以尝试hadoops globStatus而不是listStatus.Hadoop提供了两种用于处理globs的FileSystem方法:
public FileStatus[] globStatus(Path pathPattern) throws IOException
public FileStatus[] globStatus(Path pathPattern, PathFilter filter) throws IOException
Run Code Online (Sandbox Code Playgroud)
可以指定可选的PathFilter来进一步限制匹配.
有关更多说明,请在此处查看Hadoop:权威指南
希望能帮助到你..!!!
| 归档时间: |
|
| 查看次数: |
13173 次 |
| 最近记录: |