Can BerkeleyDB in perl handle hash hashes of hashes (up to n)?

I have a script that uses a hash that contains four lines as keys whose values โ€‹โ€‹are hashes. These hashes also contain four lines as keys, which also have hashes as their values. This pattern continues to levels n-1, which is determined at run time. The n-th level of hashes contains integer (unlike regular hash links) values.

I installed the BerkeleyDB module for Perl, so I can use disk space instead of RAM to store this hash. I suggested that I could just attach the hash to the database, and that would work, so I added the following to my code:

my %tags = () ; my $file = "db_tags.db" ; unlink $file; tie %tags, "BerkeleyDB::Hash", -Filename => $file, -Flags => DB_CREATE or die "Cannot open $file\n" ; 

However, I get an error message:

It is not possible to use the string ("HASH (0x1a69ad8)") as a HASH ref, and "strict refs" is used in the string getUniqSubTreeBDB.pl 31, line 1.

To test, I created a new script with the code (above) associated with the file hash. Then I added the following:

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

And everything went perfectly. Then I added:

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

And it will give almost the same error. I think BerkeleyDB cannot handle the type of data structure that I create. Maybe he was able to handle the first level (C โ†’ {}) in my test, because it was a regular regular key โ†’ scaler?

In any case, any suggestions or statements of my hypothesis will be appreciated.

+7
source share
6 answers

Use DBM :: Deep .

 my $db = DBM::Deep->new( "foo.db" ); $db->{mykey} = "myvalue"; $db->{myhash} = {}; $db->{myhash}->{subkey} = "subvalue"; print $db->{myhash}->{subkey} . "\n"; 

The code I presented yesterday will work just fine with this.

 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; 
+7
source

Not. BerkeleyDB stores pairs of one key and one value, where both are arbitrary bytes. If you save hashref as a value, it will save the hashref string representation, which is not very useful when you read it (as you noticed).

The MLDBM module can do what you describe, but it works by serializing the top-level hash file into a string and storing it in a DBM file. This means that it must read / write the entire top level hashref every time you access it or change its value.

Depending on your application, you can combine your keys in one line and use this as a key for your DBM file. The main limitation is that it is difficult to iterate over the keys of one of your internal hashes.

To do this, you can use semi - living multidimensional emulation of the array . $foo{$a,$b,$c} interpreted as $foo{join($;, $a, $b, $c)} , and this also works with related hashes.

+1
source

Not; it can only store strings. But you can use โ†’filter_fetch_value and โ†’filter_store_value to define โ€œfiltersโ€ that will automatically block arbitrary structures for strings before storing and convert back on extraction. There are similar hooks for sorting and disassembling non-linear keys.

Beware: using this method to store objects shared by subobjects will not preserve sharing. For example:

 $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 hash attached here; if it were a regular hash, two prints would both print 4 .

+1
source

While you cannot store normal multidimensional hashes in a BerkeleyDB-related hash, you can use emulated multidimensional hashes with syntax like $ tags {'C', 'G'}. This creates a single key that looks like ('C'. $ ;. 'G')

+1
source

I had the same question, found this. May be useful to you too.

Saving Data Structures as Values โ€‹โ€‹in BDB

Often, it may be interesting for us to store complex data structures: arrays, hash tables, ... whose elements can be simple values โ€‹โ€‹of references to other data structures. To do this, we need to serialize the data structure: convert it to a string that can be stored in the database, and subsequently can be converted back to the original data structure using the deserialization procedure.

Several perl modules are available to complete this serialization / deserialization process. One of the most popular is JSON :: XS. The following example shows how to use this module:

 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); 
0
source

In perl you can do this. You use links outside the first level.

 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; 

This can be found in the perl online book in chapter 13.

0
source

All Articles