Может ли BerkeleyDB в perl обрабатывать хэш хешей (до n)? - PullRequest
8 голосов
/ 21 марта 2012

У меня есть скрипт, который использует хеш, который содержит четыре строки в качестве ключей, значения которых являются хешами. Эти хэши также содержат четыре строки в качестве ключей, которые также имеют хэши в качестве значений. Этот шаблон продолжается до n-1 уровней, который определяется во время выполнения. Хэши n-го уровня содержат целочисленные (в отличие от обычной хеш-ссылки) значения.

Я установил модуль BerkeleyDB для Perl, чтобы я мог использовать место на диске вместо оперативной памяти для хранения этого хэша. Я предполагал, что смогу просто привязать хеш к базе данных, и это сработает, поэтому я добавил в свой код следующее:

my %tags = () ; 
my $file = "db_tags.db" ; 
unlink $file; 


tie %tags, "BerkeleyDB::Hash", 
        -Filename => $file, 
        -Flags => DB_CREATE
     or die "Cannot open $file\n" ;

Однако я получаю сообщение об ошибке:

Невозможно использовать строку ("HASH (0x1a69ad8)") в качестве ссылки HASH, в то время как "строгие ссылки" используются в getUniqSubTreeBDB.pl, строка 31, строка 1.

Для тестирования я создал новый скрипт с кодом (выше), который привязан к хешу к файлу. Затем я добавил следующее:

my $href = \%tags; 
$tags{'C'} = {} ;

И все прошло нормально. Затем я добавил:

$tags{'C'}->{'G'} = {} ;

И это даст примерно ту же ошибку. Я думаю, что BerkeleyDB не может обработать тип структуры данных, которую я создаю. Может быть, он смог обработать первый уровень (C -> {}) в моем тесте, потому что это был просто обычный ключ -> Scaler?

В любом случае, любые предложения или подтверждения моей гипотезы будут оценены.

Ответы [ 6 ]

9 голосов
/ 21 марта 2012

Использование DBM :: Deep .

my $db = DBM::Deep->new( "foo.db" );

$db->{mykey} = "myvalue";
$db->{myhash} = {};
$db->{myhash}->{subkey} = "subvalue";

print $db->{myhash}->{subkey} . "\n";

Код, который я вчера предоставил, будет хорошо работать с этим.

sub get_node {
   my $p = \shift;
   $p = \( ($$p)->{$_} ) for @_;
   return $p;
}

my @seqs = qw( CG CA TT CG );

my $tree = DBM::Deep->new("foo.db");
++${ get_node($tree, split //) } for @seqs;
2 голосов
/ 21 марта 2012

Нет; он может хранить только строки. Но вы можете использовать →filter_fetch_value и →filter_store_value для определения «фильтров» , которые автоматически замораживают произвольные структуры в строки перед сохранением, и конвертируют обратно при получении. Существуют аналогичные крючки для маршалинга и демаршаллинга нестроковых ключей.

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

$a = [1, 2, 3];
$g = { array => $a };
$h = { array => $a };
$db{g} = $g;
$db{h} = $h;

@$a = ();
push @{$db{g}{array}}, 4;

print @{$db{g}{array}};  # prints 1234, not 4
print @{$db{h}{array}};  # prints 123, not 1234 or 4

%db вот связанный хеш; если бы это был обычный хеш, оба print s выдали бы 4.

2 голосов
/ 21 марта 2012

Нет.BerkeleyDB хранит пары из одного ключа и одного значения, где оба являются произвольными байтовыми строками.Если вы сохраните хеш-значение в качестве значения, оно будет хранить строковое представление хеш-ссылки, что не очень полезно, когда вы читаете его обратно (как вы заметили).

MLDBM * 1004Модуль * может делать что-то, как вы описали, но он работает, сериализуя хэш-ссылку верхнего уровня в строку и сохраняя ее в файле DBM.Это означает, что он должен читать / записывать весь хэш-ключ верхнего уровня каждый раз, когда вы обращаетесь к нему или изменяете значение.

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

Для этого вы можете использовать полу устаревшую эмуляцию многомерного массива .$foo{$a,$b,$c} интерпретируется как $foo{join($;, $a, $b, $c)}, что также работает с связанными хешами.

1 голос
/ 17 февраля 2018

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

use GDBM_File;
use Storable;
use MLDBM qw(GDBM_File Storable);
my %hash;
my %level_2_hash;
my %level_3_hash1 =  (key1 => x, key2 => y, key3 => z)
my %level_3_hash2 =  (key10 => a, key20 => b, key30 => c)
$level_2_hash = (keyA => /%level_3_hash1, keyB => level_3_hash2)
$hash{key} = \%level_2_hash;

Это можно найти в онлайновой начинающей книге по Perl в главе 13.

1 голос
/ 26 декабря 2015

У меня был тот же вопрос, нашел это.Может быть полезно и для вас.

Хранение структур данных в виде значений в BDB

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

Существует несколькоДоступны модули Perl для выполнения этого процесса сериализации / десериализации.Одним из самых популярных является JSON :: XS.Следующий пример показывает, как использовать этот модуль:

use JSON::XS;

# Data to be stored
my %structure;

# Convert the data into a json string
my $json = encode_json(%structure);

# Save it in the database
$dbh->db_put($key,$json);
To retrieve the original structure, we perform the inverse operation:

# Retrieve the json string from the database
$dbh->db_get($key, $json);

# Deserialize the json string into a data structure
my $hr_structure = decode_json($json);
1 голос
/ 21 марта 2012

Хотя вы не можете хранить обычные многомерные хэши в связанном хэше BerkeleyDB, вы можете использовать эмулированные многомерные хэши с синтаксисом, таким как $ tags {'C', 'G'}. Это создает единственный ключ, который выглядит как ('C'. $;. 'G')

...