2012-03-21 16 views
7

Mam skrypt, który wykorzystuje skrót, który zawiera cztery ciągi jako klucze, których wartości są wartościami mieszającymi. Te skróty zawierają również cztery ciągi jako klucze, które również mają wartości mieszane. Ten wzorzec utrzymuje się do poziomu n-1, który określa się w czasie wykonywania. N-poziom haszu zawiera wartości całkowite (w przeciwieństwie do zwykłej wartości referencyjnej).Czy BerkeleyDB w perlu obsługuje skrót mieszania skrótów (do n)?

Zainstalowałem moduł BerkeleyDB dla Perla, więc mogę użyć miejsca na dysku zamiast pamięci RAM do przechowywania tego skrótu. Sądziłem, że mogę po prostu związać hash do bazy danych, i będzie pracować, tak I dodaje następujące do mojego kodu:

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


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

Jednakże pojawia się błąd:

nie można używać znaków ("HASH (0x1a69ad8)") jako HASH ref, a "ścisłe refs" w linii getUniqSubTreeBDB.pl 31, wiersz 1.

Aby przetestować, stworzyłem nowy skrypt, z kodem (powyżej), który był związany mieszać do pliku. Następnie dodałem:

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

I działało dobrze. Następnie dodałem:

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

I dałoby prawie taki sam błąd. Myślę, że BerkeleyDB nie poradzi sobie z rodzajem struktury danych, którą tworzę. Może był w stanie obsłużyć mój pierwszy poziom (C -> {}), ponieważ był to zwykły klucz -> skaler?

W każdym razie, wszelkie sugestie lub afirmacje mojej hipotezy byłyby docenione.

Odpowiedz

7

Użyj DBM::Deep.

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

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

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

Kod, który podałem wczoraj, działałby dobrze.

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

s/would/should /. Właściwie to nie testowałem. – ikegami

+0

Próbowałem tego, zastępując $ root = \% tagami $ root = tie $ tags, "DBM :: Deep", $ dbFile. Program działa wolniej, ale korzysta również z pamięci RAM? Myślałem, że jeśli użyjesz bazy danych, twoja pamięć RAM nie będzie używana do przechowywania hasza? – gravitas

+0

@RSinghS, Cały punkt korzystania z bazy danych polegałby na unikaniu używania pamięci, nie rozumiem, dlaczego miałaby ona korzystać z dużej ilości pamięci. – ikegami

1

Nie. BerkeleyDB przechowuje pary jednego klucza i jednej wartości, gdzie oba są arbitralne. Jeśli przechowujesz hashref jako wartość, to będzie on zapisywał reprezentację łańcuchową hashref, co nie jest zbyt przydatne, gdy ją odtworzysz (jak zauważyłeś).

Moduł może zrobić coś podobnego do tego, co opisujesz, ale działa poprzez szeregowanie hashref najwyższego poziomu w łańcuchu i przechowywanie go w pliku DBM. Oznacza to, że musi on odczytywać/zapisywać cały hash najwyższego poziomu za każdym razem, gdy uzyskujesz dostęp lub zmieniasz w nim wartość.

W zależności od aplikacji, możesz połączyć klucze w jeden ciąg i użyć go jako klucza do pliku DBM. Głównym ograniczeniem jest to, że trudno jest przechodzić przez klawisze jednego z wewnętrznych haszów.

Możesz użyć do tego półz przestarzałego multidimensional array emulation. $foo{$a,$b,$c} jest interpretowany jako $foo{join($;, $a, $b, $c)} i działa również z powiązanymi skrótami.

+0

niestety, że nie działa z '$ foo {@indexes}'. Liczba indeksów musi być znana podczas kompilacji. Mógł jednak przeliterować "join" tak jak ty. Rzecz w tym, że wcześniej zapytał, jak utworzyć wielopoziomowy hasz zamiast używać połączonego klucza. – ikegami

1

Nie; może przechowywać tylko ciągi. Ale możesz użyć funkcji →filter_fetch_value i →filter_store_value , która automatycznie zamrozi dowolne struktury na łańcuchy przed ich zapisaniem, i do konwersji z powrotem podczas pobierania. Istnieją analogiczne zaczepy do zestawiania i odczytywania kluczy nie będących ciągami.

Uwaga: używanie tej metody do przechowywania obiektów, które współdzielą podobiekty, nie zachowuje udostępniania. Na przykład:

$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 tutaj jest związany hasz; jeśli byłby to zwykły hasz, oba numery print byłyby drukowane 4.

1

Chociaż nie można zapisać normalnych wielowymiarowych skrótów w wiązanej mieszance BerkeleyDB, można użyć emulowanych wielowymiarowych skrótów o składni takiej jak $ tags {'C', 'G'}. Spowoduje to utworzenie pojedynczego klucza, który wygląda ("C". $;. "G")

0

Miałem to samo pytanie, znalazłem to. Może ci się przydać również dla ciebie.

Przechowywanie struktur danych jako wartości w BDB

Często możemy być zainteresowani przechowywania złożonych struktur danych: tablice, hashtables ... którego elementy mogą być proste wartości, odniesień do innych struktur danych. Aby to zrobić, musimy przekształcić strukturę danych do postaci szeregowej: przekształcić ją w ciąg znaków, który może być przechowywany w bazie danych, i później przekształcić z powrotem w oryginalną strukturę danych, stosując procedurę deserializacji.

Dostępnych jest kilka modułów perla do przeprowadzenia tego procesu szeregowania/deserializacji. Jednym z najbardziej popularnych jest JSON :: XS. Następny przykład pokazuje, jak korzystać z tego modułu:

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

W perlu możesz to zrobić. Korzystasz z referencji poza pierwszym poziomem.

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; 

ten można znaleźć w internetowym zaczynają perla książki w rozdziale 13.