Ответ 1
В большинстве случаев вы можете сохранить строку в качестве ключа в хеше. Однако, когда вы получаете это большое, это действительно не очень эффективно. В этом случае вам лучше использовать базу данных.
Попробуйте базу данных Berkeley, которая используется для включения в Unix (BDB). Теперь он, по-видимому, принадлежит Oracle.
Perl может использовать модуль BerkeleyDB для общения с базой данных BDB. Фактически вы можете даже tie хеш файл Perl в базу данных BDB. Как только это будет сделано, вы можете использовать обычные хеши Perl для доступа и изменения базы данных.
BDB довольно устойчив. Биткойны используют его, а также SpamAssassin, поэтому очень возможно, что он может обрабатывать тип базы данных, которую вы должны создать, чтобы найти повторяющиеся строки. Если у вас уже установлен DBD, написание программы для обработки вашей задачи не займет много времени. Если это не сработает, вы бы не потратили слишком много времени на это.
Единственное, что я могу придумать, это использовать базу данных SQL, которая будет медленнее и сложнее.
Добавление
Возможно, я уже думал об этом...
Я решил попробовать простой хеш. Здесь моя программа:
#! /usr/bin/env perl
use strict;
use warnings;
use feature qw(say);
use autodie;
use constant DIR => "/usr/share/dict";
use constant WORD_LIST => qw(words web2a propernames connectives);
my %word_hash;
for my $count (1..100) {
for my $file (WORD_LIST) {
open my $file_fh, "<", DIR . "/$file";
while (my $word = <$file_fh>) {
chomp $word;
$word_hash{"$file-$word-$count"} = $word;
}
}
}
Файлы, которые читаются, содержат в общей сложности около 313 000 строк. Я делаю это 100 раз, чтобы получить хэш с 31 300 000 ключей в нем. Это примерно так же неэффективно, как может быть. Каждый ключ будет уникальным. Объем памяти будет массивным. Тем не менее,...
Это сработало. Потребовалось около 10 минут, чтобы бежать, несмотря на массовую неэффективность программы, и она превысила около 6 гигабайт. Однако большая часть из них была в виртуальной памяти. Как ни странно, несмотря на то, что он работал, поглощая память и принимая 98% процессора, моя система не сильно замедляла все это. Наверное, вопрос в том, какой тип производительности вы ожидаете? Если вы потратите около 10 минут на выполнение, это не так уж и важно для вас, и вы не ожидаете, что эта программа будет использоваться так часто, а затем, может быть, пойти на простоту и использовать простой хеш.
Теперь я загружаю DBD из Oracle, компилирую его и устанавливаю. Я попробую одну и ту же программу, используя DBD, и посмотрю, что произойдет.
Использование базы данных BDB
После выполнения работы я думаю, что если у вас установлен MySQL, использование Perl DBI будет проще. Мне пришлось:
- Загрузите Berkeley DB из Oracle, и вам нужна учетная запись Oracle. Я не помню свой пароль и сказал ему, чтобы отправить мне электронное письмо. Никогда не получал электронное письмо. Я потратил 10 минут, пытаясь запомнить мой адрес электронной почты.
- После загрузки он должен быть скомпилирован. Найденные направления для компиляции для Mac, и это казалось довольно простым.
- Запустился запуск CPAN. Заканчивается, что CPAN ищет
/usr/local/BerkeleyDB
, и он был установлен как/usr/local/BerkeleyDB.5.3
. Создание ссылки устранило проблему.
Все сказали, около 1/2 часа, чтобы установить BerkeleyDB. После установки, изменение моей программы было довольно простым:
#! /usr/bin/env perl
use strict;
use warnings;
use feature qw(say);
use autodie;
use BerkeleyDB;
use constant {
DIR => "/usr/share/dict",
BDB_FILE => "bdb_file",
};
use constant WORD_LIST => qw(words web2a propernames connectives);
unlink BDB_FILE if -f BDB_FILE;
our %word_hash;
tie %word_hash, "BerkeleyDB::Hash",
-Filename => BDB_FILE,
-Flags => DB_CREATE
or die qq(Cannot create DBD_Database file ") . BDB_FILE . qq("\n);
for my $count (1..10) {
for my $file (WORD_LIST) {
open my $file_fh, "<", DIR . "/$file";
while (my $word = <$file_fh>) {
chomp $word;
$word_hash{"$file-$word-$count"} = $word;
}
}
}
Все, что мне нужно было сделать, это добавить несколько строк.
Запуск программы был разочарованием. Это было не быстрее, но намного, намного медленнее. Это заняло более 2 минут, в то время как использование чистого хэша заняло всего 13 секунд.
Однако он использовал намного меньше памяти. В то время как старая программа сожрала гигабайты, версия BDB почти не использовала мегабайт. Вместо этого он создал файл базы данных 20 МБ.
Но, в эти дни ВМ и дешевая память, она что-то достигла? В старые времена перед виртуальной памятью и хорошей обработкой памяти программа разбивала бы ваш компьютер, если бы использовала всю память (и память измерялась в мегабайтах, а не в гигабайтах). Теперь, если ваша программа хочет больше памяти, чем доступно, ей просто предоставляется виртуальная память.
Итак, в конце концов, использование базы данных Berkeley не является хорошим решением. Все, что я сохранил во время программирования с помощью tie
, было потрачено впустую на процесс установки. И это было медленно.
Использование BDB просто использовало DBD файл вместо памяти. Современная ОС будет делать то же самое и быстрее. Зачем работать, когда ОС будет обрабатывать его для вас?
Единственная причина использовать базу данных - если ваша система действительно не имеет необходимых ресурсов. 200 миллионов строк - большой файл, но современная ОС, вероятно, будет в порядке. Если ваша система действительно не имеет ресурса, используйте базу данных SQL в другой системе, а не базу данных DBD.