Как искать общие пароли из двух файлов размером 20 ГБ? - PullRequest
0 голосов
/ 29 ноября 2011

У меня есть два файла размером 20 ГБ.Я должен удалить общие пароли из одного файла.

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

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

я принял 20 символов в качестве максимальной длины паролей

эта программа еще не эффективна.

Пожалуйста, помогите сделать его эффективным, если это возможно ....

Пожалуйста, дайте мне несколько советов для эффективной сортировки этого файла 20 ГБ .....

в 64-битной версииПоток с 8 ГБ ОЗУ и процессором i3 Quard .....

Я только что проверил свою программу с двумя файлами размером 10 МБ.Это заняло около 2,66 часа без каких-либо опций оптимизации..... согласно моей программе, потребуется около 7-8 часов для проверки каждого пароля размером 20 ГБ после разделения, сортировки и двоичного поиска .....

Могу ли я улучшить его временную сложность?я имею в виду, могу ли я заставить его работать более "быстрее" ???

Ответы [ 5 ]

1 голос
/ 30 ноября 2011

Для предыдущего SE вопроса"Какой алгоритм использовать для удаления дубликатов?" Я описал алгоритм для, вероятно, аналогичной проблемы, за исключением файлов 50 ГБ вместо 20 ГБ. Метод быстрее, чем сортировка больших файлов в этой задаче.

Вот адаптация метода к вашей проблеме. Давайте назовем исходные два файла A и B, и предположим, что A больше, чем B. Я не понимаю из вашего описания проблемы, что должно произойти, если или когда будет обнаружен дубликат, но в следующем я предполагаю, что вы хотите оставить файл A без изменений, и удалить из B все элементы, которые также находятся в A. Я также предполагаю, что записи в пределах A определены с самого начала как уникальные в пределах A, и аналогично для B. Если это не так, метод требует больше адаптация и примерно вдвое больше ввода / вывода.

Предположим, что вы можете поместить 1 / k'th файла A в память и по-прежнему иметь место для других необходимых структур данных. Весь файл B затем может быть обработан за k или менее проходов, как показано ниже, и это может быть намного быстрее, чем сортировка любого файла, в зависимости от длины строки и констант алгоритма сортировки. Сортировка средних значений O (n ln n) и приведенный ниже процесс - это O (k n) наихудший случай. Например, если строки в среднем состоят из 10 символов и имеется n = 2G строк, ln (n) ~ 21,4, вероятно, будет примерно в 4 раза хуже, чем O (k n), если k=5. (Константы алгоритма все равно могут изменить ситуацию в любом случае, но с быстрой хэш-функцией метод имеет хорошие константы.)

Процесс:

  1. Пусть Q = B ( т.е. переименовать или скопировать B в Q)
  2. Выделите несколько гигабайт для рабочего буфера W и около гигабайта для хэш-таблицы H. Откройте входные файлы A и Q, выходной файл O и временный файл T. Перейдите к шагу 2.
  3. Заполнить рабочий буфер W чтением из файла A.
  4. Для каждой строки L в W хеш L в H такой, что H [hash [L]] индексирует строку L.
  5. Считать все Q, используя H, чтобы обнаружить дубликаты, записать недубликаты во временный файл T.
  6. Закройте и удалите Q, переименуйте T в Q, откройте новый временный файл T.
  7. Если EOF (A), переименуйте Q в B и выйдите, иначе перейдите к шагу 2.

Обратите внимание, что после каждого прохода (, то есть в начале шага 6) ни одна из строк в Q не является дубликатами того, что до сих пор считывалось из A. Таким образом, 1 / k'th исходного файла обрабатывается за проход, и обработка занимает k проходов. Также обратите внимание, что хотя обработка будет связана с вводом / выводом, вы можете читать и писать в несколько раз быстрее с большими буферами ( например 8MB), чем построчно. Алгоритм, как указано выше, не включает в себя детали буферизации или способы обработки частичных строк в больших буферах.

Вот простой пример производительности: предположим, что A, B - это файлы размером 20 ГБ, каждый из которых содержит около 2 ГБ паролей, а дубликаты встречаются довольно редко. Также предположим, что 8 ГБ ОЗУ достаточно для того, чтобы рабочий буфер W был размером 4 ГБ, оставляя достаточно места для хэш-таблицы H, чтобы можно было сказать .6G 4-байтовые записи. Каждый проход (шаги 2-5) читает 20% A и читает и записывает почти весь B, на каждом проходе отсеивая любой пароль, уже замеченный в A. I / O составляет приблизительно 120 ГБ чтения (1 * A + 5 * B) , 100 ГБ написано (5 * B).

Вот более сложный пример производительности: предположим, что около 1G случайно распределенных паролей в B продублировано в A, а все остальное, как в предыдущем примере. Тогда ввод / вывод составляет около 100 ГБ для чтения и 70 ГБ для записи (20 + 20 + 18 + 16 + 14 + 12 и 18 + 16 + 14 + 12 + 10 соответственно).

1 голос
/ 29 ноября 2011

Проверить внешнюю сортировку. См. http://www.umbrant.com/blog/2011/external_sorting.html с кодом в конце страницы (https://github.com/umbrant/extsort).

Идея, лежащая в основе внешней сортировки, заключается в выборе и сортировке равноудаленных выборок из файла. Затем разделение файла в точках выборки, сортировка разделов и объединение результатов.

example numbers = [1, 100, 2, 400, 60, 5, 0, 4]
example samples (distance 4) = 1, 60
chunks = {0,1,2,5,4} , {60, 100, 400}

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

0 голосов
/ 30 ноября 2011

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

sort the files using any suitable sorting utility
open files A and B for reading
read wordA from A
read wordB from B
while (A not EOF and B not EOF)
{
    if (wordA < wordB)
      write wordA to output
      read wordA from A
    else if (wordA > wordB)
      read wordB from B
    else
      /* match found, don't output wordA */
      read wordA from A
}
while (A not EOF) /* output remaining words */
{
    write wordA to output
    read wordA from A
}
0 голосов
/ 30 ноября 2011

Если c ++ это вариант для вас, готовый к использованию STXXL должен иметь возможность обрабатывать ваш набор данных.

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

0 голосов
/ 29 ноября 2011

Примерно так:

  1. Объединить два файла.
  2. Используйте sort для сортировки итогового результата.
  3. Используйте uniq для удаления дубликатов изотсортированный итог.
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...