Java: Как быстро извлечь совпадающие строки из большого текстового файла?

1

Несмотря на то, что в моей работе есть много предлагаемых решений, я все еще не удовлетворен временем выполнения, которое они требуют в моем специальном случае.

Рассмотрим большой текстовый файл 35G в формате FASTA, например:

>Protein_1 So nice and cute little fella
MTTKKCLQKFHLESLGKLGDSFLKYAISIQLFKSYENHYEGLPSIKKNKIISNAALFKLG 
YARKILRFIRNEPFDLKVGLIPSDNSQAYNFGKEFLMPSVKMCSRVK*
>Protein_2 Fancy incredible description of its function
MADDSKFCFFLVSTFLLLAVVVNVTLAANYVPGDDILLNCGGPDNLPDADGRKWGTDIGS
[…] etc.

Мне нужно извлечь только строки >.

Использование grep '>' proteins.fasta > protein_descriptions.txt для достижения этого занимает всего пару минут.

Но с использованием Java 7 это уже работает более 90 минут:

public static void main(String[] args) throws Exception {
    BufferedReader fastaIn = new BufferedReader(new FileReader(args[0]));
    List<String> l = new ArrayList<String>();
    String str;
    while ((str = fastaIn.readLine()) != null) {
        if (str.startsWith(">")) {
            l.append(str);
        }
    }
    fastaIn.close();
    // …
}

Кто-нибудь имеет представление о том, как ускорить это до производительности grep?

Ваша помощь будет высоко оценена. Ура!

  • 0
    Рассматривали ли вы идею простого вызова «grep» как внешнего процесса? Просто прочитайте выходной файл / stdout, и вы получите почти такую же производительность.
  • 0
    Я бы попытался реализовать парсер SAX или StAX.
Показать ещё 3 комментария
Теги:
performance
text-files
large-files
fasta

3 ответа

1

Программа biojava.org предоставляет читателю fasta. Для чтения огромных файлов вам нужно будет рассмотреть использование SeekableByteChannell и использование ByteBuffers. В библиотеке biojava используются байтовые буферы.

1

Если вы напишете его в outfile немедленно, вместо того, чтобы накапливать объекты в памяти, это улучшит производительность (и будет больше похоже на то, что вы сделали с grep в любом случае).

...
BufferedWriter fastaOut = new BufferedWriter(new FileWriter(args[1]));
...
while ((str = fastaIn.readLine()) != null) {
        if (str.startsWith(">")) {
            fastaOut.write(str);
            fastaOut.newLine();
        }
    }
...    
fastaOut.close();
  • 1
    Почему этот ответ был отклонен? Я уверен, что это решение. Если ваш файл имеет размер 35 ГиБ, вам понадобится много памяти для вашего ArrayList . В худшем случае это взорвет вашу физическую память, и ваша ОС начнет обмениваться. И когда это происходит, производительность резко падает. Но даже если ваша память достаточно велика, производительность JVM вполне может упасть, так как она получает все больше и больше работы с управлением памятью и сборкой мусора. Используйте статистику своей ОС, чтобы узнать, сколько памяти и процессора использует ваш процесс.
  • 0
    Я понимаю вашу точку зрения. Мой вариант использования немного сложнее. Я хотел бы сохранить список описаний белков с помощью ObjectOutputStream , чтобы впоследствии можно было загружать его очень быстро. Как мне это сделать?
Показать ещё 2 комментария
0

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

  • 0
    Это звучит как хорошее решение. Но как мне убедиться, что я разбил файл на куски, которые заканчиваются точно на разрыв строки? Иначе я мог бы пропустить хотя бы часть описания белка, не так ли?
  • 0
    Ваша строка поиска состоит всего из 2 символов ... Вы можете просто начать с X / n - 1 и прочитать X / n + 2 символа; что должно иметь дело с этим делом

Ещё вопросы

Сообщество Overcoder
Наверх
Меню