perl中的BerkeleyDB可以处理散列哈希值(最多为n)吗?

时间:2012-03-21 16:27:38

标签: database perl hash berkeley-db

我有一个使用散列的脚本,该散列包含四个字符串作为其值为哈希值的键。这些哈希值还包含四个字符串作为键,它们也具有哈希值作为其值。此模式持续高达n-1级别,这是在运行时确定的。第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" ;

然而,我收到错误:

在getUniqSubTreeBDB.pl第31行第1行使用“strict refs”时,不能使用字符串(“HASH(0x1a69ad8)”)作为HASH引用。

为了测试,我创建了一个新脚本,其代码(上面)与哈希绑定到文件。然后我添加了以下内容:

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

它运行良好。然后我补充道:

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

它会产生几乎相同的错误。我在想BerkeleyDB无法处理我正在创建的数据结构类型。也许它能够在我的测试中处理第一级(C-> {}),因为它只是一个常规键 - >定标器?

无论如何,对我的假设的任何建议或肯定都将不胜感激。

6 个答案:

答案 0 :(得分:9)

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

答案 1 :(得分:2)

没有。 BerkeleyDB存储一对密钥和一对值的对,其中两个都是任意的字节串。如果您将hashref存储为值,它将存储hashref的字符串表示形式,当您将其读回时(如您所注意到的那样),它不是非常有用。

MLDBM模块可以执行您所描述的操作,但它可以通过将顶级hashref序列化为字符串并将其存储在DBM文件中来实现。这意味着每次访问或更改其中的值时,它必须读取/写入整个顶级hashref。

根据您的应用程序,您可以将密钥组合成一个字符串,并将其用作DBM文件的密钥。与此相关的主要限制是难以迭代其中一个内部哈希的键。

您可以使用半过时的multidimensional array emulation$foo{$a,$b,$c}被解释为$foo{join($;, $a, $b, $c)},并且也适用于并列哈希。

答案 2 :(得分:2)

没有;它只能存储字符串。但您可以使用→filter_fetch_value→filter_store_value to 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

答案 3 :(得分:1)

虽然您无法在BerkeleyDB绑定哈希中存储正常的多维哈希,但您可以使用带有$ tags {'C','G'}等语法的模拟多维哈希。这会创建一个看起来像('C'。$;。'G')

的单个键

答案 4 :(得分:1)

我有同样的问题,发现了这一点。也可能对你有用。

将数据结构存储为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);

答案 5 :(得分:1)

在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章的在线开始perl书中找到。

相关问题