【问题标题】:Can BerkeleyDB in perl handle a hash of hashes of hashes (up to n)?perl 中的 BerkeleyDB 可以处理散列的散列(最多 n 个)吗?
【发布时间】:2023-03-22 12:01:01
【问题描述】:

我有一个使用哈希的脚本,其中包含四个字符串作为键,其值为哈希。这些散列还包含四个字符串作为键,它们的值也有散列。这种模式一直持续到 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 行使用“严格引用”时,不能使用字符串 ("HASH(0x1a69ad8)") 作为 HASH 引用。

为了测试,我创建了一个新脚本,其中的代码(上图)与文件的散列相关联。然后我添加了以下内容:

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

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

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

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

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

【问题讨论】:

    标签: database perl hash berkeley-db


    【解决方案1】:

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

    【讨论】:

    • s/会/应该/。我实际上并没有测试它。
    • 我尝试用 $root = tie $tags, "DBM::Deep", $dbFile 替换 $root = \%tags。程序运行更慢,但它也使用 RAM?我认为如果您使用数据库,您的 RAM 将不会用于存储哈希?
    • @RSinghS,使用数据库的全部意义在于避免使用内存,我不明白为什么会使用大量内存。
    • 好吧,很酷,现在用的不多。感谢您的帮助。
    【解决方案2】:

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

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

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

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

    【讨论】:

    • 不幸的是,这不适用于$foo{@indexes}。索引的数量必须在编译时知道。不过,他可以像你一样拼出join。问题是,他之前问过如何创建多级哈希而不是使用连接键。
    【解决方案3】:

    没有;它只能存储字符串。但是您可以使用 →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 这里是一个绑定哈希;如果是普通哈希,则两个 prints 都会打印 4

    【讨论】:

      【解决方案4】:

      虽然您不能将普通的多维哈希存储在 BerkeleyDB 绑定哈希中,但您可以使用具有类似 $tags{ 'C', 'G'} 的语法的模拟多维哈希。这将创建一个看起来像 ('C' . $; . 'G')

      【讨论】:

        【解决方案5】:

        我有同样的问题,找到了这个。可能对你也有用。

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

        【讨论】:

          【解决方案6】:

          在 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 入门书籍中找到。

          【讨论】:

            猜你喜欢
            • 2012-10-25
            • 1970-01-01
            • 2011-03-13
            • 1970-01-01
            • 2013-03-14
            • 2019-01-13
            • 1970-01-01
            • 1970-01-01
            • 2014-05-19
            相关资源
            最近更新 更多