Alt-CWB-ambs
view release on metacpan or search on metacpan
lib/CWB/Encoder.pm view on Meta::CPAN
$bnc->group("corpora"); # optional: group and access
$bnc->perm("640"); # permissions for newly created files
$bnc->memory(400); # use up to 400 MB of RAM (default: 75)
$bnc->validate(0); # disable validation for faster indexing
$bnc->debug(1); # enable debugging output
$bnc->make("word", "pos"); # build index & compress
$bnc->makeall; # process all p-attributes
$bnc = new CWB::Encoder "BNC";
$bnc->registry("/path/to/registry"); # will try to guess otherwise
$bnc->dir("/path/to/data/directory"); # directory for corpus data files
$bnc->overwrite(1); # may overwrite existing files / directories
$bnc->longname("British National Corpus"); # optional
$bnc->info("Line1.\nLine2.\n..."); # optional multi-line info text
$bnc->charset("latin1"); # defaults to latin1
$bnc->language("en"); # defaults to ??
$bnc->group("corpora"); # optional: group and access permissions
$bnc->perm("640"); # for newly created files & directories
$bnc->p_attributes("word"); # declare postional atts (no default!)
$bnc->p_attributes(qw<pos lemma>); # may be called repeatedly
$bnc->null_attributes("teiHeader"); # declare null atts (ignored)
$bnc->s_attributes("s"); # s-attributes in cwb-encode syntax
$bnc->s_attributes(qw<div0* div1*>);# * = store annotations (-V)
$bnc->s_attributes("bncDoc:0+id"); # recursion & XML attributes
$bnc->decode_entities(0); # don't decode XML entities (with -x flag)
$bnc->undef_symbol("__UNDEF__"); # mark missing values like cwb-encode
$bnc->memory(400); # use up to 400 MB of RAM (default: 75)
$bnc->validate(0); # disable validation for faster indexing
$bnc->verbose(1); # print some progress information
$bnc->debug(1); # enable debugging output
$bnc->encode(@files); # encoding, indexing, and compression
$pipe = $bnc->encode_pipe; # can also feed input text from Perl script
while (...) {
print $pipe "$line\n";
}
$bnc->close_pipe;
=head1 DESCRIPTION
This package contains modules for the automatic encoding and indexing
of CWB corpora.
B<CWB::Indexer> builds indices for some or all positional attributes
of an existing corpus (using the B<cwb-makeall> tool). In addition,
these attributes are automatically compressed (using the
B<cwb-huffcode> and B<cwb-compress-rdx> tools). Compression and
indexing is interleaved to minimise the required amount of temporary
disk space, and a B<make>-like system ensures that old index files are
automatically updated.
B<CWB::Encoder> automates all steps necessary to encode a CWB corpus
(which includes cleaning up old files, running B<cwb-encode>, editing
the registry entry, indexing & compressing positional attributes, and
setting access permissions). Both modules can be set up with a few
simple method calls. Full descriptions are given separately in the
following sections.
=cut
## ======================================================================
## automatic creation, compression and updating of CWB index files (for p-attributes)
## ======================================================================
package CWB::Indexer;
use CWB;
use Carp;
# makefile-like rules for creating / updating components
# TRIGGER .. update component when one of these comps exists & is newer
# NEEDED .. componentes required by command below
# CREATES .. these files will be created by COMMAND
# COMMAND .. shell command to create this component
# interpolates '#C' (corpus id), '#A' (attribute name), '#R' (registry flag),
# '#M' (memory limit), '#T' (no validate), '#V' (validate)
# (issues "can't create" error message if COMMAND starts with "ERROR")
# DELETE .. delete these components when target exist or has been created
our %RULES =
(
DIR => {
TRIGGER => [],
NEEDED => [],
CREATES => [],
COMMAND => "ERROR: Corpus data directory must be created manually.",
DELETE => [],
},
CORPUS => {
TRIGGER => [],
NEEDED => [],
CREATES => [],
COMMAND => "ERROR: You must run the cwb-encode tool first.",
DELETE => [],
},
LEXICON => {
TRIGGER => [],
NEEDED => [],
CREATES => [],
COMMAND => "ERROR: You must run the cwb-encode tool first.",
DELETE => [],
},
LEXIDX => {
TRIGGER => [],
NEEDED => [],
CREATES => [],
COMMAND => "ERROR: You must run the cwb-encode tool first.",
DELETE => [],
},
FREQS => {
TRIGGER => [qw<CORPUS LEXICON LEXIDX>],
lib/CWB/Encoder.pm view on Meta::CPAN
my ($self, $perm) = @_;
$self->{PERM} = $perm;
}
=item $idx->memory($mbytes);
Set approximate memory limit for B<cwb-makeall> command, in MBytes.
The memory limit defaults to 75 MB, which is a reasonable value for
systems with at least 128 MB of RAM.
=cut
sub memory {
my ($self, $mem) = @_;
croak "CWB::Indexer: memory limit ($mem) must be positive integer number (aborted).\n"
unless $mem =~ /^[1-9][0-9]*$/;
$self->{MEMORY} = $mem;
}
=item $idx->validate(0);
Turn off validation of index and compressed files, which may give
substantial speed improvements for larger corpora.
=cut
sub validate {
my ($self, $yesno) = @_;
$self->{VALIDATE} = $yesno;
}
=item $idx->debug(1);
Activate debugging output (on STDERR).
=cut
sub debug {
my ($self, $yesno) = @_;
$self->{DEBUG} = $yesno;
}
# internal method: get full pathname of a component file
sub filename {
my ($self, $att, $comp) = @_;
my $path = $self->{FILES}->{$att}->{$comp};
croak "CWB::Indexer: can't determine filename for component $att/$comp (aborted).\n"
unless defined $path;
return $path;
}
# internal method: make single component (recursively builds dependencies)
sub make_comp {
my ($self, $att, $comp) = @_;
my $rule = $RULES{$comp};
croak "CWB::Indexer: no rule found for component $comp (aborted).\n"
unless defined $rule;
my ($trigger, $needed, $creates, $command, $delete) =
@$rule{qw<TRIGGER NEEDED CREATES COMMAND DELETE>};
my $update = 0; # check whether component needs to be created / updated
my $file = $self->filename($att, $comp);
if (not -f $file) {
print STDERR "CWB::Indexer: component $att/$comp does not exist -> create\n"
if $self->{DEBUG};
$update = 1; # file does not exist -> create
}
else {
my $age = -M $file;
foreach my $t (@$trigger) { # check for triggers that are newer than target
my $t_file = $self->filename($att, $t);
if (-f $t_file) {
my $t_age = -M $t_file;
if ($t_age < $age) {
$update = 1; # trigger is newer -> update
print STDERR "CWB::Indexer: component $att/$t is newer than $att/$comp -> update\n"
if $self->{DEBUG};
}
}
}
}
if ($update) { # (re-)create component if necessary
print STDERR
"CWB::Indexer: make_comp($att, $comp)\n",
"CWB::Indexer: creating component file $file\n"
if $self->{DEBUG};
foreach my $c (@$creates) { # delete old target files (first, to make room for intermediate files)
my $f = $self->filename($att, $c);
if (-f $f) {
unlink $f;
croak "CWB::Indexer: Can't delete file $f (aborted).\n"
if -e $f;
print STDERR "CWB::Indexer: deleting file $f\n"
if $self->{DEBUG};
}
}
foreach my $c (@$needed) { # recursively create/update prerequisites
$self->make_comp($att, $c);
}
if ($command =~ s/^\s*ERROR\s*(:\s*)?//) {
croak
"CWB::Indexer: Can't create component $att/$comp ($file)\n",
" $command\n";
}
$command =~ s/\#C/$self->{NAME}/g; # substitute variables in $command
$command =~ s/\#A/$att/g;
$command =~ s/\#R/$self->{REGISTRY}/g;
$command =~ s/\#M/-M $self->{MEMORY}/g;
$command =~ s/\#T/($self->{VALIDATE}) ? "" : "-T"/eg;
$command =~ s/\#V/($self->{VALIDATE}) ? "-V" : ""/eg;
print STDERR "CWB::Indexer: exec: $command\n"
if $self->{DEBUG};
CWB::Shell::Cmd $command; # execute creation command
my $perm = $self->{PERM}; # check that target file(s) exist and set permissions
my $group = $self->{GROUP};
foreach my $c (@$creates) {
my $f = $self->filename($att, $c);
croak "CWB::Indexer: Creation of component $att/$c ($f) failed (aborted).\n"
unless -s $f;
if ($perm) {
my $cmd = "chmod $perm '$f'";
print STDERR "CWB::Indexer: exec: $cmd\n"
if $self->{DEBUG};
CWB::Shell::Cmd $cmd;
}
if ($group) {
my $cmd = "chgrp $group '$f'";
print STDERR "CWB::Indexer: exec: $cmd\n"
if $self->{DEBUG};
CWB::Shell::Cmd $cmd;
}
}
print STDERR "CWB::Indexer: component $att/$comp has been created successfully\n"
if $self->{DEBUG};
}
# always run the cleanup so that unneccessary files are automatically deleted
foreach my $c (@$delete) { # delete intermediate components that are no longer needed
my $f = $self->filename($att, $c);
if (-f $f) {
print STDERR "CWB::Indexer: deleting file $f\n"
if $self->{DEBUG};
unlink $f;
croak "CWB::Indexer: Can't delete intermediate file $f (aborted).\n"
if -f $f;
}
}
}
=item $idx->make($att1, $att2, ...);
Process one or more positional attributes. An index is built for each
attribute and the data files are compressed. Missing files are
re-created (if possible) and old files are updated automatically.
=cut
sub make {
my $self = shift;
my $corpus = $self->{NAME};
foreach my $att (@_) {
my $type = $self->{TYPES}->{$att};
croak "CWB::Indexer: $corpus.$att is not a positional attribute (aborted).\n"
unless $type and $type eq "P";
print STDERR "CWB::Indexer: make($corpus.$att)\n"
if $self->{DEBUG};
foreach my $comp (@NEEDED) {
$self->make_comp($att, $comp);
}
print STDERR "CWB::Indexer: attribute $corpus.$att was indexed successfully\n"
if $self->{DEBUG};
}
}
=item $idx->makeall;
Process all positional attributes of the corpus.
=cut
sub makeall {
my $self = shift;
foreach my $att (keys %{$self->{TYPES}}) {
$self->make($att)
if $self->{TYPES}->{$att} eq "P";
}
}
=back
=cut
## ======================================================================
## automatic encoding, indexing, and compression of corpora
## ======================================================================
package CWB::Encoder;
use CWB;
use Carp;
use DirHandle;
=head1 CWB::Encoder METHODS
=over 4
=item $enc = new CWB::Encoder $corpus;
Create a new B<CWB::Encoder> object for the specified corpus. Note
that the registry directory cannot be passed directly to the
constructor (use the B<registry> method instead).
=cut
( run in 1.596 second using v1.01-cache-2.11-cpan-7fcb06a456a )