2012-03-21 73 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章