2012-03-21 87 views
7

我有一個使用散列的腳本,它包含四個字符串作爲其值爲散列的鍵。這些散列還包含四個字符串作爲鍵,它們也具有散列值。這種模式繼續達到n-1級,這是在運行時確定的。散列的第n級包含整數(與通常的散列引用相對)值。Perl中的BerkeleyDB可以處理散列哈希(最多n個)的散列嗎?

我安裝了Perl的BerkeleyDB模塊,所以我可以使用磁盤空間而不是RAM來存儲這個散列。我以爲,我可以簡單地綁散列到一個數據庫,它會工作,所以我增加了以下我的代碼:

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


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

但是,我得到的錯誤:

不能用string (「HASH(0x1a69ad8)」)作爲HASH ref,而在getUniqSubTreeBDB.pl第31行第1行使用「strict refs」。

爲了測試,我創建了一個新腳本,散列到文件。然後我添加以下內容:

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

它運行良好。然後我補充說:

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

它會給出幾乎相同的錯誤。我在想,BerkeleyDB無法處理我創建的數據結構類型。也許它能夠在我的測試中處理第一級(C - > {}),因爲它只是一個常規密鑰 - >縮放器?

無論如何,任何建議或肯定我的假設將不勝感激。

回答

7

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

s/would/should /。我沒有真正測試它。 – ikegami 2012-03-21 18:07:35

+0

我試着用$ root = tie $ tags,「DBM :: Deep」,$ dbFile替換$ root = \%標籤。 程序運行速度比較慢,但它也使用內存?我認爲如果你使用數據庫你的RAM不會被用來存儲散列? – gravitas 2012-03-22 17:04:39

+0

@RSinghS,使用一個數據庫,將避免使用內存的整點,我不明白爲什麼它會使用大量內存。 – ikegami 2012-03-22 17:43:16

1

編號BerkeleyDB存儲一對密鑰和一個值,其中都是任意字節串。如果你存儲一個hashref作爲值,它將存儲hashref的字符串表示,當你讀回它時(如你注意到的),這不是非常有用。

MLDBM模塊可以執行類似於您所描述的操作,但它通過將頂級hashref序列化爲字符串並將其存儲在DBM文件中起作用。這意味着每次訪問或更改其中的一個值時,它都必須讀取/寫入整個頂層hashref。

根據您的應用程序,您可能能夠將您的密鑰組合成單個字符串,並將其用作DBM文件的密鑰。主要的限制是難以迭代你的內部哈希鍵之一。

您可能會爲此使用半過時的multidimensional array emulation$foo{$a,$b,$c}被解釋爲$foo{join($;, $a, $b, $c)},並且還與綁定散列一起工作。

+0

不幸的是,這並不與'$ foo的{@indexes}'工作開始perl的書。編譯時必須知道索引的數量。雖然他可以像你一樣拼出「加入」。問題是,他以前曾問過如何創建多層散列而不是使用聯合鍵。 – ikegami 2012-03-21 18:09:25

1

否;它只能存儲字符串。但是您可以使用→filter_fetch_value→filter_store_valueto define "filters",它們會在存儲之前自動將任意結構凍結到字符串,並在提取時將其轉換回來。有類似的掛鉤用於編組和非編組非字符串鍵。

但要小心:使用此方法存儲共享子對象的對象不會保留共享。例如:

$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都將打印4

1

儘管無法在BerkeleyDB捆綁哈希中存儲常規多維哈希值,但您可以使用具有像$ tags {'C','G'}之類的語法的模擬多維哈希值。這將創建一個單一的按鍵,看起來像( 'C' $; 'G')

0

我有同樣的問題,發現這一點。可能對你有用。

存儲數據結構值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); 
0

在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; 

這可以在網上找到在第13章