Поліпшення продуктивності для прив’язки до величезного файлу


10

У мене є FILE_A, який налічує понад 300 000 рядків, і FILE_B, який має понад 30 мільйонів рядків. Я створив сценарій Bash, який обробляє кожен рядок у FILE_A в FILE_B і записує результат grep в новий файл.

Весь цей процес займає понад 5 годин.

Як я можу покращити ефективність свого сценарію?

Я використовую grep -F -m 1як команду grep. FILE_A виглядає так:

123456789 
123455321

і FILE_B виглядає так:

123456789,123456789,730025400149993,
123455321,123455321,730025400126097,

Тож у Bash у мене є whileцикл, який вибирає наступний рядок у FILE_A та обробляє його у FILE_B. Коли шаблон знайдено у FILE_B, я записую його у файл result.txt.

while read -r line; do
   grep -F -m1 $line 30MFile
done < 300KFile

Відповіді:


17

Спробуйте використовувати grep --file==FILE_A. Він майже напевно завантажує шаблони в пам'ять, тобто сканує FILE_B лише один раз.

grep -F -m1 --file==300KFile 30MFile

Це спрацювало б лише за умови, що у мене достатньо пам'яті?
rogerio_marcio

Чесно кажучи, я ще не пробував це на файлах такого розміру, але я вважаю, що це повинно значно підвищити вашу швидкість. Якщо ви працюєте на сучасній машині, у вас не повинно виникнути проблем із збереженням файлу 300 КБ в пам'яті. (Або 30-мільйонний з цього приводу.)
Гурт Робота

коли я використав опцію -f (--file), я в основному відтворив 30MFile. Я щось роблю не так?
rogerio_marcio

Гммм ... може, у 300Kfile було порожнє рядок у ньому?
Гурт Робота

прямо на місці! це було все! що працювало чудово, закінчилося за 30 секунд! Дякую тобі!!
rogerio_marcio

2

Ось відповідь Perl для нащадків. Я звичайно роблю це для зіставлення ліній 1М до 30-35М рядків. Потрібно пройти близько 10 секунд.

По-перше, хеш-код FILE_A:

my %simple_hash;
open my $first_file, '<', 'FILE_A' or die "What have you done?! $!";
while (<$first_file>) {
  chomp;                 ## Watch out for Windows newlines
  $simple_hash{$_} = 1;  ## There may be an even faster way to define this
}
close $first_file;

Потім, якщо ваш великий файл розміщений і ви знаєте, через який стовпець потрібно пройти, перевірте, чи існує лише хеш-ключ, коли ви запустите FILE_B, що набагато, набагато швидше, ніж перевірка рівності чи відповідності регулярних виразів:

open my $second_file, '<', 'FILE_B' or die "Oh no, not again.. $!";
while (<$second_file>) {
  my ($col1, undef) = split ',';
  if (exists($simple_hash{$col1}) {
    print $_;
  }
}
close $second_file;

Якщо ваш більший цільовий файл не в змозі проаналізувати, то цей скрипт втрачає значення, оскільки стільки його швидкості виходить з того, що не потрібно запускати механізм регулярних виразів .


1

Якщо ви не заперечуєте над тим, хто займається програмуванням, подумайте про використання суфіксних дерев (або варіанту).

Ви можете попередньо обробити,FILE_B використовуючи алгоритм Укконена в лінійний час. Потім ви запитуєте кожен рядок за FILE_Aчасом лінійно по довжині рядка і отримуєте всі номери рядків, які відповідають (можливо, знадобиться адаптувати дерево tad), які ви можете записати у файл результатів.

Вся процедура працює в часі O (n + Nm), якщо n - довжина FILE_B, N- це кількість рядків у, FILE_Aа m - довжина найдовшої лінії в FILE_A- це, по суті, лінійний час виконання. Перемагає квадратичний час, який потребує ваш оригінальний підхід за величиною.


1

--mmapНещодавно я знайшов прапор, не мав можливості його перевірити, але буду радий почути про ваші висновки. Ось опис зі сторінки man:

--mmap If  possible, use the mmap(2) system call to read input, instead
      of the default read(2) system call.  In some situations,  --mmap
      yields  better performance.  However, --mmap can cause undefined
      behavior (including core dumps) if an input file  shrinks  while
      grep is operating, or if an I/O error occurs.

Дивіться це чи це для отримання додаткової інформації про mmap.


Я обов'язково спробую це зробити, і я дам вам знати, як це відбувається. Наскільки ймовірним є те, що я зіткнуся з основним смітником?
rogerio_marcio

@rogerio_marcio Добре, як я розумію, "якщо файл скорочується під час роботи grep, або якщо виникає помилка вводу / виводу". Не дуже, мабуть, але ви повинні це краще знати. (Якщо, як я вважаю, файл не чіпається під час grep - цього не повинно статися)
Ramzi Kahil

Для тестування цієї --mmapдози нічого не скидає, я б порекомендував пробіг --mmapі без. А потім скористайтеся wcдля того, щоб побачити, що у вас однаковий обсяг випуску - це має бути надійний тест, враховуючи, що ми пробігли 2 рази grep, і просто прапор відрізнявся.
Рамзі Кахіл

@rogerio_marcio Ви пробували це? Будь-які уявлення?
Рамзі Кахіль

-1

чому б ви не помістили цей файл у бази даних, насправді добре виконувати ефективне об'єднання, приєднання хеш-вкладеного циклу. І вони дуже добре використовують віртуальну пам'ять


Все, що ви робите з усіма іншими відповідями, - це винахід колеса бази даних
Ендіз Сміт
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.