2012-03-21 6 views
7

해시를 사용하는 스크립트가 있습니다. 해시를 사용하는 스크립트는 값이 해시 인 키로 4 개의 문자열을 포함합니다. 이 해시에는 네 개의 문자열이 값으로 해시가있는 키로 포함되어 있습니다. 이 패턴은 실행시 결정되는 n-1 레벨까지 계속됩니다. n 번째 레벨의 해시에는 정수가 포함됩니다 (일반적인 해시 - 참조와 반대).Perl에서 BerkeleyDB가 해시 해시의 해시를 처리 할 수 ​​있습니까 (최대 n)?

이 해시를 저장하기 위해 RAM 대신 디스크 공간을 사용할 수 있도록 Perl 용 BerkeleyDB 모듈을 설치했습니다. 나는 단순히 데이터베이스에 해시를 묶을 수 있고, 작동한다고 가정, 그래서 나는 내 코드에 다음과 같은 추가 :

문자열을 사용할 수 없습니다

그러나

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


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

, 나는 오류 ("HASH (0x1a69ad8)")을 HASH ref로 사용하고 "strict refs"는 getUniqSubTreeBDB.pl 31 줄 1 행에서 사용합니다.

테스트하려면 위 코드를 묶은 새 스크립트를 만들었습니다 파일에 해쉬하기. 그런 다음 다음을 추가했습니다.

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

+0

나는 $ root = \ % 태그를 $ root = tie $ tags, "DBM :: Deep", $ dbFile로 바꾸어서 이것을 시도했다. 프로그램이 더 느리게 실행되지만 RAM을 사용하고 있습니까? 데이터베이스를 사용할 경우 RAM이 해시를 저장하는 데 사용되지 않을 것이라고 생각했습니다. – gravitas

+0

@RSinghS, 데이터베이스 사용의 전체 요점은 메모리 사용을 피하는 것이고 많은 메모리를 사용해야하는 이유는 없습니다. – ikegami

1

번호 BerkeleyDB는 하나의 키와 하나의 값의 쌍을 저장합니다. 둘 다 임의의 bytestrings입니다. 값으로 hashref를 저장하면 hashref의 문자열 표현을 저장합니다.이 값은 다시 읽었을 때 유용하지 않습니다.

MLDBM 모듈은 설명하는 것처럼 할 수 있지만 최상위 hashref를 문자열로 serialize하고이를 DBM 파일에 저장하면 작동합니다. 즉, 값을 액세스하거나 값을 변경할 때마다 최상위 해시 레퍼런스 전체를 읽고 쓰는 것을 의미합니다.

응용 프로그램에 따라 키를 단일 문자열로 결합하여 DBM 파일의 키로 사용할 수 있습니다. 이것의 주된 한계는 내부 해시 중 하나의 키를 반복하는 것이 어렵다는 것입니다.

이 경우 반쯤 사용하지 않는 multidimensional array emulation을 사용할 수 있습니다. $foo{$a,$b,$c}$foo{join($;, $a, $b, $c)}으로 해석되며 묶인 해시에서도 작동합니다.

+0

제 13 장에 펄 책을 시작 온라인에서 찾을 수 있습니다. 인덱스의 수는 컴파일시 알려 져야합니다. 당신이했던 것처럼 그는 '조인'을 철자 할 수 있습니다. 문제는 이전에 조인 된 키를 사용하는 대신 멀티 레벨 해시를 만드는 방법을 물었습니다. – ikegami

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의 값으로 데이터 구조를 저장, 우리는 복잡한 데이터 구조 저장에 관심이있을 수 : 배열, 해시 테이블을 ... 요소가 다른 데이터 구조에 대한 참조의 간단한 값이 될 수 있습니다. 이렇게하려면 데이터 구조를 직렬화해야합니다. 데이터베이스에 저장할 수있는 문자열로 변환하고 나중에 deserialization 프로 시저를 사용하여 원래 데이터 구조로 다시 변환 할 수 있습니다.

이 직렬화/직렬화 프로세스를 수행하는 데 사용할 수있는 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; 

는`$ foo는 {@indexes}`작동하지 않습니다 불행히도