Подтвердить что ты не робот

Подстановочный знак в 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

В моем случае каталог хранит 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

Проблема

Я не хочу использовать команду оболочки и не могу найти эквивалент этой команды выше в Java API. Когда я пытаюсь реализовать цикл, я получаю ужасную производительность. Я хочу, по крайней мере, производительность командной строки (вокруг 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 и использованию массивов он работает быстрее (около 12 секунд). Однако код более сложный и сложнее адаптироваться к различным ситуациям. Самое главное, производительность по-прежнему в 3 - 4 раза медленнее, чем версия командной строки!


Вопрос

Что мне здесь не хватает? Какой самый быстрый способ получить результаты, которые я хочу?


Обновления

2014.07.09 - 13:38

Предлагаемый ответ Mukesh S, по-видимому, является наилучшим возможным API-интерфейсом.

В приведенном выше примере конец кода выглядит следующим образом:

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

Это лучший и эффективный код, который я мог бы придумать до сих пор, но по-прежнему не выполняет, а также версию оболочки.

4b9b3361

Ответ 1

Вместо listStatus вы можете попробовать hasoops globStatus. Hadoop предоставляет два метода FileSystem для обработки глобусов:

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

Дополнительный PathFilter может быть указан для ограничения последующих совпадений.

Для более подробного описания вы можете проверить Hadoop: Окончательное руководство здесь

Надеюсь, это поможет..!!!