Оптимизация производительности поиска данных в файловой системе - PullRequest
0 голосов
/ 19 ноября 2018

У меня есть хранилище, связанное с сетью, где около 5 миллионов текстовых файлов связано с примерно 3 миллионами транзакций. Размер общих данных составляет около 3,5 ТБ. Я должен искать в этом месте, чтобы узнать, доступен ли файл, связанный с транзакцией, и должен сделать два отдельных отчета в виде CSV-файла «доступные файлы» и «недоступные файлы». Мы Все еще в JAVA 6. Проблема, с которой я сталкиваюсь, так как мне приходится искать в этом месте рекурсивно, у меня уходит в среднем около 2 минут на поиск в этом месте из-за огромных размеров. Я использую Java I / O API для рекурсивного поиска, как показано ниже. Есть ли способ улучшить производительность?

File searchFile(File location, String fileName) {
     if (location.isDirectory()) {
         File[] arr = location.listFiles();
         for (File f : arr) {
             File found = searchFile(f, fileName);
             if (found != null)
                 return found;
         }
     } else {
         if (location.getName().equals(fileName)) {
             return location;
         }
     }
     return null;
}

Ответы [ 4 ]

0 голосов
/ 19 ноября 2018
  • Поиск в каталоге или связанном с сетью хранилище - это кошмар. Это занимает много времени, когда каталог слишком большой / глубины.Как и в Java 6, так что вы можете следовать старомодному подходу.Перечислите все файлы в CSV-файле, как показано ниже.
  • например

    найти.-type f -name '* .txt' >> test.csv.(если unix)

    dir / b / s * .txt> test.csv (если Windows)

  • Теперь загрузите этот CSV-файл в карту, чтобы иметь индекскак имя файла.Загрузка файла займет некоторое время, так как он будет огромным, но как только вы загрузите, тогда поиск по карте (так как это будет имя файла) будет намного быстрее и значительно сократит время поиска.
0 голосов
/ 19 ноября 2018

Я не знаю ответа, но с точки зрения алгоритма, ваша программа имеет худшую сложность.для каждой отдельной транзакции выполняется поиск всех файлов (5 миллионов).у вас 3 миллиона транзакций.

Я предлагаю перебирать файлы (5 миллионов файлов) и создавать индекс на основе имени файла.затем повторяйте транзакции и ищите индекс вместо полного сканирования.Или могут быть сторонние бесплатные инструменты, которые могут индексировать большую файловую систему, а затем к этому индексу можно получить доступ из внешнего приложения (в данном случае вашего java-приложения).если вы не можете найти такой инструмент, лучше его придумать (тогда вы можете построить индекс оптимальным образом, который соответствует вашим требованиям).

0 голосов
/ 19 ноября 2018

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

По существу:

void buildIndex(Map index, File baseDir) {
    if (location.isDirectory()) {
        File[] arr = location.listFiles();
        for (File f : arr) {
            buildIndex(index, f);
        }
    } else {
        index.put(f.getName(), f);
    }
}

Теперь, когда у вас есть индекс, поиск файлов становится тривиальным.

Теперь у вас есть файлы на карте, вы также можете использовать операцию Set, чтобы найти пересечение:

Map index = new HashMap();
buildIndex(index, ...);
Set fileSet = index.keySet();
Set transactionSet = ...;
Set intersection = new HashSet(fileSet);
fileSet.retainAll(transactionSet);

При желании, если сам индекс слишком велик для хранения в памяти, вы можете создать его в базе данных SQLite.

0 голосов
/ 19 ноября 2018

Вы можете использовать NIO FileVisitor, доступный в Java 6.

Path findTransactionFile(Path root) {
    Path transactionFile = null;
    Files.walkFileTree(root, new SimpleFileVisitor<Path>() {
        @Override
        public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) throws IOException {
            if (/* todo dir predicate*/ false) {
                return FileVisitResult.SKIP_SUBTREE; // optimization
            }
            return FileVisitResult.CONTINUE;
        }

        @Override
        public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
            if (/* todo file predicate*/ true) {
                transactionFile = file;
                return FileVisitResult.TERMINATE; // found    
            }
            return FileVisitResult.CONTINUE;
        }
    });

    return transactionFile;
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...