blob: 53f07656564f8a33a7c1664d8fb4aebd2df1af73 [file] [log] [blame]
Nils Diewald2db9ad02013-10-29 19:26:43 +00001#!/usr/bin/env perl
2use strict;
3use warnings;
Akron941c1a62016-02-23 17:41:41 +01004use FindBin;
5BEGIN { unshift @INC, "$FindBin::Bin/../lib" };
6use File::Spec::Functions qw/catfile catdir/;
7use Getopt::Long qw/GetOptions :config no_auto_abbrev/;
Nils Diewald7364d1f2013-11-05 19:26:35 +00008use Benchmark qw/:hireswallclock/;
9use IO::Compress::Gzip qw/$GzipError/;
Nils Diewald2db9ad02013-10-29 19:26:43 +000010use Log::Log4perl;
Akron941c1a62016-02-23 17:41:41 +010011use Pod::Usage;
Akron11c80302016-03-18 19:44:43 +010012use Cache::FastMmap;
Akron941c1a62016-02-23 17:41:41 +010013use Directory::Iterator;
Akron93d620e2016-02-05 19:40:05 +010014use KorAP::XML::Krill;
Akron941c1a62016-02-23 17:41:41 +010015use KorAP::XML::Archive;
Akron93d620e2016-02-05 19:40:05 +010016use KorAP::XML::Tokenizer;
Akron941c1a62016-02-23 17:41:41 +010017use Parallel::ForkManager;
Akron75ba57d2016-03-07 23:36:27 +010018# TODO: use Parallel::Loops
Akron08385f62016-03-22 20:37:04 +010019# TODO: make output files
Akron93d620e2016-02-05 19:40:05 +010020
Akron941c1a62016-02-23 17:41:41 +010021# CHANGES:
22# ----------------------------------------------------------
23# 2013/11/25
24# - Initial release
25#
26# 2014/10/29
27# - Merges foundry data to create indexer friendly documents
28#
Akron93d620e2016-02-05 19:40:05 +010029# 2016/02/04
30# - renamed to korapxml2krill
31# - added Schreibgebrauch support
Akron069bd712016-02-12 19:09:06 +010032#
33# 2016/02/12
34# - fixed foundry skipping
Akron941c1a62016-02-23 17:41:41 +010035# - Support overwrite in archive processing
Akron150b29e2016-02-14 23:06:48 +010036#
37# 2016/02/14
38# - Added version information
Akron941c1a62016-02-23 17:41:41 +010039# - Added support for archive files
40#
41# 2016/02/15
42# - Fixed temporary directory bug
43# - Improved skipping before unzipping
44# - Added EXPERIMENTAL concurrency support
45#
46# 2016/02/23
47# - Merge korapxml2krill and korapxml2krill_dir
Akrone10ad322016-02-27 10:54:26 +010048#
49# 2016/02/27
50# - Added extract function
Akron35db6e32016-03-17 22:42:22 +010051#
52# 2016/03/17
53# - Added meta switch
Akron11c80302016-03-18 19:44:43 +010054#
55# 2016/03/18
56# - Added meta data caching
Akron2cfe8092016-06-24 17:48:49 +020057#
Akronf3f0c942016-06-27 13:27:14 +020058# 2016/06/27
Akron2cfe8092016-06-24 17:48:49 +020059# - Added multi archive support
60# - Added prefix negation support
Akronf3f0c942016-06-27 13:27:14 +020061# - Added Malt#Dependency support
Akron8b990522016-07-06 16:45:57 +020062#
63# 2016/07/06
64# - Added MDParser#Dependency
Akron941c1a62016-02-23 17:41:41 +010065# ----------------------------------------------------------
Akron069bd712016-02-12 19:09:06 +010066
Akron8b990522016-07-06 16:45:57 +020067our $LAST_CHANGE = '2016/07/06';
Akron941c1a62016-02-23 17:41:41 +010068our $LOCAL = $FindBin::Bin;
69our $VERSION_MSG = <<"VERSION";
70Version $KorAP::XML::Krill::VERSION - diewald\@ids-mannheim.de - $LAST_CHANGE
71VERSION
72
73
74# Parse comand
75my $cmd;
76our @ARGV;
77if ($ARGV[0] && index($ARGV[0], '-') != 0) {
78 $cmd = shift @ARGV;
Akron150b29e2016-02-14 23:06:48 +010079};
Akron93d620e2016-02-05 19:40:05 +010080
Akron08385f62016-03-22 20:37:04 +010081my (@skip, @sigle, @input);
Akron35db6e32016-03-17 22:42:22 +010082my $text;
Akrone10ad322016-02-27 10:54:26 +010083
Akron941c1a62016-02-23 17:41:41 +010084# Parse options from the command line
Nils Diewald7364d1f2013-11-05 19:26:35 +000085GetOptions(
Akron08385f62016-03-22 20:37:04 +010086 'input|i=s' => \@input,
Akron941c1a62016-02-23 17:41:41 +010087 'output|o=s' => \(my $output),
88 'overwrite|w' => \(my $overwrite),
Akron35db6e32016-03-17 22:42:22 +010089 'meta|m=s' => \(my $meta),
Akron941c1a62016-02-23 17:41:41 +010090 'token|t=s' => \(my $token_base),
91 'gzip|z' => \(my $gzip),
Akrone10ad322016-02-27 10:54:26 +010092 'skip|s=s' => \@skip,
93 'sigle|sg=s' => \@sigle,
Akron11c80302016-03-18 19:44:43 +010094 'cache|c=s' => \(my $cache_file = 'korapxml2krill.cache'),
95 'cache-size|cs=s' => \(my $cache_size = '50m'),
96 'cache-delete|cd!' => \(my $cache_delete = 1),
97 'cache-init|ci!' => \(my $cache_init = 1),
Akron941c1a62016-02-23 17:41:41 +010098 'log|l=s' => \(my $log_level = 'ERROR'),
Akronc13a1702016-03-15 19:33:14 +010099 'anno|a=s' => \(my @anno),
Akron941c1a62016-02-23 17:41:41 +0100100 'primary|p!' => \(my $primary),
101 'pretty|y' => \(my $pretty),
102 'jobs|j=i' => \(my $jobs = 0),
103 'help|h' => sub {
104 pod2usage(
105 -sections => 'NAME|SYNOPSIS|ARGUMENTS|OPTIONS',
106 -verbose => 99,
107 -msg => $VERSION_MSG,
108 );
109 },
110 'version|v' => sub {
111 pod2usage(
112 -verbose => 0,
113 -msg => $VERSION_MSG
114 )
115 }
Nils Diewald7364d1f2013-11-05 19:26:35 +0000116);
117
Akron941c1a62016-02-23 17:41:41 +0100118my %ERROR_HASH = (
119 -sections => 'NAME|SYNOPSIS|ARGUMENTS|OPTIONS',
120 -verbose => 99,
121 -msg => $VERSION_MSG,
122 -exit => 1
123);
Nils Diewald7364d1f2013-11-05 19:26:35 +0000124
Akron941c1a62016-02-23 17:41:41 +0100125# Input has to be defined
Akron08385f62016-03-22 20:37:04 +0100126pod2usage(%ERROR_HASH) unless @input;
Nils Diewald7364d1f2013-11-05 19:26:35 +0000127
Nils Diewald7364d1f2013-11-05 19:26:35 +0000128
Akron941c1a62016-02-23 17:41:41 +0100129# Initialize log4perl object
Nils Diewald7364d1f2013-11-05 19:26:35 +0000130Log::Log4perl->init({
131 'log4perl.rootLogger' => uc($log_level) . ', STDERR',
132 'log4perl.appender.STDERR' => 'Log::Log4perl::Appender::ScreenColoredLevels',
133 'log4perl.appender.STDERR.layout' => 'PatternLayout',
134 'log4perl.appender.STDERR.layout.ConversionPattern' => '[%r] %F %L %c - %m%n'
135});
136
137my $log = Log::Log4perl->get_logger('main');
138
Akron941c1a62016-02-23 17:41:41 +0100139
140# Get file name based on path information
141sub get_file_name ($) {
Akron08385f62016-03-22 20:37:04 +0100142 my $i = $input[0];
Akron941c1a62016-02-23 17:41:41 +0100143 my $file = shift;
Akron62557602016-06-27 14:10:13 +0200144 $file =~ s!^/?tmp/[^/]+!!;
Akron08385f62016-03-22 20:37:04 +0100145 $file =~ s/^?\/?$i//;
Akron941c1a62016-02-23 17:41:41 +0100146 $file =~ tr/\//-/;
147 $file =~ s{^-+}{};
148 return $file;
Nils Diewald59094f22014-11-05 18:20:50 +0000149};
150
Akron941c1a62016-02-23 17:41:41 +0100151
152# Write file
153sub write_file {
154 my $anno = shift;
155 my $file = get_file_name $anno;
156
157 # TODO: This should be done directly with a data structure! KorAP::XML::Wrap
158
Akron08385f62016-03-22 20:37:04 +0100159 my $call = 'perl ' . $LOCAL . '/korapxml2krill';
160 $call .= ' -i ' . $anno;
161 $call .= ' -o ' . $output . '/' . $file . '.json';
Akron941c1a62016-02-23 17:41:41 +0100162 $call .= '.gz -z' if $gzip;
Akron35db6e32016-03-17 22:42:22 +0100163 $call .= ' -m ' . $meta if $meta;
Akron941c1a62016-02-23 17:41:41 +0100164 $call .= ' -w' if $overwrite;
165 $call .= ' -t ' . $token_base if $token_base;
166 $call .= ' -l ' . $log_level if $log_level;
Akron11c80302016-03-18 19:44:43 +0100167 $call .= ' -c ' . $cache_file;
168 $call .= ' -cs ' . $cache_size;
169 $call .= ' --no-cache-delete'; # Don't delete the cache
170 $call .= ' --no-cache-init'; # Don't initialize the cache
Akron941c1a62016-02-23 17:41:41 +0100171 $call .= ' --no-primary ' if $primary;
172 $call .= ' -y ' . $pretty if $pretty;
Akronc13a1702016-03-15 19:33:14 +0100173 $call .= ' -a ' . $_ foreach @anno;
Akron941c1a62016-02-23 17:41:41 +0100174 $call .= ' -s ' . $_ foreach @skip;
175 system($call);
176 return "$file";
Nils Diewald7364d1f2013-11-05 19:26:35 +0000177};
178
Nils Diewald2db9ad02013-10-29 19:26:43 +0000179
Akrone10ad322016-02-27 10:54:26 +0100180# Convert sigle to path construct
181s!^\s*([^_]+?)_([^\.]+?)\.(.+?)\s*$!$1/$2/$3! foreach @sigle;
182
Akron941c1a62016-02-23 17:41:41 +0100183# Process a single file
184unless ($cmd) {
Akron08385f62016-03-22 20:37:04 +0100185 my $input = $input[0];
Nils Diewald59094f22014-11-05 18:20:50 +0000186
Akron941c1a62016-02-23 17:41:41 +0100187 # Can't print gzip to STDOUT
188 pod2usage(%ERROR_HASH) if $gzip && !$output;
Nils Diewald2db9ad02013-10-29 19:26:43 +0000189
Akron941c1a62016-02-23 17:41:41 +0100190 my %skip;
191 $skip{lc($_)} = 1 foreach @skip;
Nils Diewald2db9ad02013-10-29 19:26:43 +0000192
Akron941c1a62016-02-23 17:41:41 +0100193 # Ignore processing
194 if (!$overwrite && $output && -e $output) {
195 $log->trace($output . ' already exists');
196 exit(0);
Nils Diewald7364d1f2013-11-05 19:26:35 +0000197 };
Akron941c1a62016-02-23 17:41:41 +0100198
199 BEGIN {
200 $main::TIME = Benchmark->new;
201 $main::LAST_STOP = Benchmark->new;
202 };
203
204 sub stop_time {
205 my $new = Benchmark->new;
206 $log->trace(
207 'The code took: '.
208 timestr(timediff($new, $main::LAST_STOP)) .
209 ' (overall: ' . timestr(timediff($new, $main::TIME)) . ')'
210 );
211 $main::LAST_STOP = $new;
212 };
213
214 # Create and parse new document
215 $input =~ s{([^/])$}{$1/};
Akron35db6e32016-03-17 22:42:22 +0100216 my $doc = KorAP::XML::Krill->new(
217 path => $input,
Akron11c80302016-03-18 19:44:43 +0100218 meta_type => ($meta // 'I5'),
219 cache => Cache::FastMmap->new(
220 share_file => $cache_file,
221 cache_size => $cache_size,
222 init_file => $cache_init
223 )
Akron35db6e32016-03-17 22:42:22 +0100224 );
Akron941c1a62016-02-23 17:41:41 +0100225
226 unless ($doc->parse) {
227 $log->warn($output . " can't be processed - no document data");
228 exit(0);
229 };
230
231 my ($token_base_foundry, $token_base_layer) = (qw/OpenNLP Tokens/);
232 if ($token_base) {
233 ($token_base_foundry, $token_base_layer) = split /#/, $token_base;
234 };
235
236 # Get tokenization
237 my $tokens = KorAP::XML::Tokenizer->new(
238 path => $doc->path,
239 doc => $doc,
240 foundry => $token_base_foundry,
241 layer => $token_base_layer,
242 name => 'tokens'
243 );
244
245 # Unable to process base tokenization
246 unless ($tokens->parse) {
247 $log->error($output . " can't be processed - no base tokenization");
248 exit(0);
249 };
250
251 my @layers;
252 push(@layers, ['Base', 'Sentences']);
253 push(@layers, ['Base', 'Paragraphs']);
254
255 # Connexor
256 push(@layers, ['Connexor', 'Morpho']);
257 push(@layers, ['Connexor', 'Syntax']);
258 push(@layers, ['Connexor', 'Phrase']);
259 push(@layers, ['Connexor', 'Sentences']);
260
261 # CoreNLP
262 push(@layers, ['CoreNLP', 'NamedEntities']);
263 push(@layers, ['CoreNLP', 'Sentences']);
264 push(@layers, ['CoreNLP', 'Morpho']);
265 push(@layers, ['CoreNLP', 'Constituency']);
266
267 # DeReKo
268 push(@layers, ['DeReKo', 'Structure']);
269
270 # Glemm
271 push(@layers, ['Glemm', 'Morpho']);
272
273 # Malt
Akronf3f0c942016-06-27 13:27:14 +0200274 push(@layers, ['Malt', 'Dependency']);
Akron941c1a62016-02-23 17:41:41 +0100275
Akron8b990522016-07-06 16:45:57 +0200276 # MDParser
277 push(@layers, ['MDParser', 'Dependency']);
278
Akron941c1a62016-02-23 17:41:41 +0100279 # Mate
280 push(@layers, ['Mate', 'Morpho']);
281 push(@layers, ['Mate', 'Dependency']);
282
283 # OpenNLP
284 push(@layers, ['OpenNLP', 'Morpho']);
285 push(@layers, ['OpenNLP', 'Sentences']);
286
287 # Schreibgebrauch
288 push(@layers, ['Sgbr', 'Lemma']);
289 push(@layers, ['Sgbr', 'Morpho']);
290
291 # TreeTagger
292 push(@layers, ['TreeTagger', 'Morpho']);
293 push(@layers, ['TreeTagger', 'Sentences']);
294
295 # XIP
296 push(@layers, ['XIP', 'Morpho']);
297 push(@layers, ['XIP', 'Constituency']);
298 push(@layers, ['XIP', 'Sentences']);
299 push(@layers, ['XIP', 'Dependency']);
300
301
302 if ($skip{'#all'}) {
Akronc13a1702016-03-15 19:33:14 +0100303 foreach (@anno) {
Akron941c1a62016-02-23 17:41:41 +0100304 $tokens->add(split('#', $_));
Nils Diewald7364d1f2013-11-05 19:26:35 +0000305 stop_time;
Nils Diewald2db9ad02013-10-29 19:26:43 +0000306 };
Nils Diewald7364d1f2013-11-05 19:26:35 +0000307 }
308 else {
Akron941c1a62016-02-23 17:41:41 +0100309 # Add to index file - respect skipping
310 foreach my $info (@layers) {
311 # Skip if Foundry or Foundry#Layer should be skipped
312 unless ($skip{lc($info->[0])} || $skip{lc($info->[0]) . '#' . lc($info->[1])}) {
313 $tokens->add(@$info);
314 stop_time;
315 };
316 };
Nils Diewald2db9ad02013-10-29 19:26:43 +0000317 };
318
Akron941c1a62016-02-23 17:41:41 +0100319 my $file;
Akron35db6e32016-03-17 22:42:22 +0100320 my $print_text = ($pretty ? $tokens->to_pretty_json($primary) : $tokens->to_json($primary));
Akron941c1a62016-02-23 17:41:41 +0100321
322 if ($output) {
323
324 if ($gzip) {
325 $file = IO::Compress::Gzip->new($output, Minimal => 1);
326 }
327 else {
328 $file = IO::File->new($output, "w");
329 };
330
331 $file->print($print_text);
332 $file->close;
333 }
334
335 else {
336 print $print_text . "\n";
337 };
338
Akron11c80302016-03-18 19:44:43 +0100339 # Delete cache file
340 unlink($cache_file) if $cache_delete;
341
Akron941c1a62016-02-23 17:41:41 +0100342 stop_time;
Nils Diewald7364d1f2013-11-05 19:26:35 +0000343}
Nils Diewald59094f22014-11-05 18:20:50 +0000344
Akrone10ad322016-02-27 10:54:26 +0100345# Extract XML files
346elsif ($cmd eq 'extract') {
347
348 pod2usage(%ERROR_HASH) unless $output;
349
Akrone10ad322016-02-27 10:54:26 +0100350 if ($output && (!-e $output || !-d $output)) {
351 print "Directory '$output' does not exist.\n\n";
352 exit(0);
353 };
354
Akronb0c88db2016-06-29 16:33:18 +0200355 # TODO: Support sigles and full archives
Akron08385f62016-03-22 20:37:04 +0100356
Akronb0c88db2016-06-29 16:33:18 +0200357 if (-f($input[0]) && (my $archive = KorAP::XML::Archive->new($input[0]))) {
Akrone10ad322016-02-27 10:54:26 +0100358
359 unless ($archive->test_unzip) {
360 print "Unzip is not installed or incompatible.\n\n";
361 exit(1);
362 };
363
Akronb0c88db2016-06-29 16:33:18 +0200364 # Add further annotation archived
365 $archive->attach($_) foreach @input;
366
Akrone10ad322016-02-27 10:54:26 +0100367 # Iterate over all given sigles and extract
368 foreach (@sigle) {
369 print "$_ ";
Akronb0c88db2016-06-29 16:33:18 +0200370# print '' . ($archive->extract('./'. $_, $output) ? '' : 'not ');
371 print '' . ($archive->extract('./' . $_, $output) ? '' : 'not ');
Akrone10ad322016-02-27 10:54:26 +0100372 print "extracted.\n";
373 };
374
375 print "\n";
376 exit(1);
Akronb0c88db2016-06-29 16:33:18 +0200377 }
378 else {
379 $log->error('Unable to extract from primary archive ' . $input[0]);
Akrone10ad322016-02-27 10:54:26 +0100380 };
381}
382
Akron941c1a62016-02-23 17:41:41 +0100383# Process an archive
384elsif ($cmd eq 'archive') {
Nils Diewald2db9ad02013-10-29 19:26:43 +0000385
Akrone10ad322016-02-27 10:54:26 +0100386 # TODO: Support sigles
387
Akron941c1a62016-02-23 17:41:41 +0100388 pod2usage(%ERROR_HASH) unless $output;
389
390 if ($output && (!-e $output || !-d $output)) {
391 print "Directory '$output' does not exist.\n\n";
392 exit(0);
393 };
394
395 # Zero means: everything runs in the parent process
396 my $pool = Parallel::ForkManager->new($jobs);
397
398 my $count = 0; # Texts to process
399 my $iter = 1; # Current text in process
400
401 # Report on fork message
402 $pool->run_on_finish (
403 sub {
404 my ($pid, $code) = shift;
405 my $data = pop;
Akron08385f62016-03-22 20:37:04 +0100406 print 'Convert ['. ($jobs > 0 ? "\$$pid:" : '') .
Akron941c1a62016-02-23 17:41:41 +0100407 ($iter++) . "/$count]" .
408 ($code ? " $code" : '') .
409 " $$data\n";
410 }
411 );
412
413 my $t;
414 print "Reading data ...\n";
415
Akron11c80302016-03-18 19:44:43 +0100416 unless (Cache::FastMmap->new(
417 share_file => $cache_file,
418 cache_size => $cache_size,
419 init_file => $cache_init
420 )) {
421 print "Unable to intialize cache '$cache_file'\n\n";
422 exit(1);
423 };
424
Akron941c1a62016-02-23 17:41:41 +0100425 # Input is a directory
Akron08385f62016-03-22 20:37:04 +0100426 if (-d $input[0]) {
427 my $it = Directory::Iterator->new($input[0]);
Akron941c1a62016-02-23 17:41:41 +0100428 my @dirs;
429 my $dir;
430
431 while (1) {
432 if (!$it->is_directory && ($dir = $it->get) && $dir =~ s{/data\.xml$}{}) {
433 push @dirs, $dir;
434 $it->prune;
435 };
436 last unless $it->next;
437 };
438
439 print "Start processing ...\n";
440 $t = Benchmark->new;
441 $count = scalar @dirs;
442
443 DIRECTORY_LOOP:
444 for (my $i = 0; $i < $count; $i++) {
445
446 unless ($overwrite) {
447 my $filename = catfile(
448 $output,
449 get_file_name($dirs[$i]) . '.json' . ($gzip ? '.gz' : '')
450 );
451
452 if (-e $filename) {
453 $iter++;
454 print "Skip $filename\n";
455 next;
456 };
457 };
458
459 # Get the next fork
460 my $pid = $pool->start and next DIRECTORY_LOOP;
461 my $msg;
462
463 $msg = write_file($dirs[$i]);
464 $pool->finish(0, \$msg);
465 };
466 }
467
468 # Input is a file
Akron29866ac2016-06-24 16:40:47 +0200469 elsif (-f($input[0]) && (my $archive = KorAP::XML::Archive->new($input[0]))) {
Akron941c1a62016-02-23 17:41:41 +0100470 unless ($archive->test_unzip) {
471 print "Unzip is not installed or incompatible.\n\n";
472 exit(1);
473 };
474
Akron08385f62016-03-22 20:37:04 +0100475 # Add further annotation archived
Akron29866ac2016-06-24 16:40:47 +0200476 $archive->attach($_) foreach @input;
Akron08385f62016-03-22 20:37:04 +0100477
Akron941c1a62016-02-23 17:41:41 +0100478 print "Start processing ...\n";
479 $t = Benchmark->new;
480 my @dirs = $archive->list_texts;
481 $count = scalar @dirs;
482
483 ARCHIVE_LOOP:
484 for (my $i = 0; $i < $count; $i++) {
485
486 # Split path information
487 my ($prefix, $corpus, $doc, $text) = $archive->split_path($dirs[$i]);
488
489 unless ($overwrite) {
Akron62557602016-06-27 14:10:13 +0200490
491 # This is not correct!!
Akron941c1a62016-02-23 17:41:41 +0100492 my $filename = catfile(
493 $output,
Akron62557602016-06-27 14:10:13 +0200494 get_file_name(
495 catfile($corpus, $doc, $text)
496 . '.json' . ($gzip ? '.gz' : '')
497 )
Akron941c1a62016-02-23 17:41:41 +0100498 );
499
500 if (-e $filename) {
501 $iter++;
502 print "Skip $filename\n";
503 next;
504 };
505 };
506
507 # Get the next fork
508 my $pid = $pool->start and next ARCHIVE_LOOP;
509
510 # Create temporary file
511 my $temp = File::Temp->newdir;
512
513 my $msg;
514
515 # Extract from archive
516 if ($archive->extract($dirs[$i], $temp)) {
517
518 # Create corpus directory
Akron08385f62016-03-22 20:37:04 +0100519 my $input = catdir("$temp", $corpus);
Akron941c1a62016-02-23 17:41:41 +0100520
521 # Temporary directory
522 my $dir = catdir($input, $doc, $text);
523
524 # Write file
525 $msg = write_file($dir);
526
527 $temp = undef;
528 $pool->finish(0, \$msg);
529 }
530 else {
531
532 $temp = undef;
533 $msg = "Unable to extract " . $dirs[$i] . "\n";
534 $pool->finish(1, \$msg);
535 };
536 };
537 }
538
539 else {
540 print "Input is neither a directory nor an archive.\n\n";
541 };
542
543 $pool->wait_all_children;
544
Akron11c80302016-03-18 19:44:43 +0100545 # Delete cache file
546 unlink($cache_file) if $cache_delete;
547
Akron941c1a62016-02-23 17:41:41 +0100548 print "Done.\n";
549 print timestr(timediff(Benchmark->new, $t))."\n\n";
550}
551
552# Unknown command
553else {
554 warn "Unknown command '$cmd'.\n\n";
555 pod2usage(%ERROR_HASH);
556}
Nils Diewald2db9ad02013-10-29 19:26:43 +0000557
558__END__
Akron941c1a62016-02-23 17:41:41 +0100559
560=pod
561
562=encoding utf8
563
564=head1 NAME
565
Akronf7ad89e2016-03-16 18:22:47 +0100566korapxml2krill - Merge KorapXML data and create Krill documents
Akron941c1a62016-02-23 17:41:41 +0100567
568
569=head1 SYNOPSIS
570
Akronc13a1702016-03-15 19:33:14 +0100571 $ korapxml2krill -z --input <directory> --output <filename>
572 $ korapxml2krill archive -z --input <directory> --output <directory>
573 $ korapxml2krill extract --input <directory> --output <filename> --sigle <SIGLE>
Akron941c1a62016-02-23 17:41:41 +0100574
575
576=head1 DESCRIPTION
577
578L<KorAP::XML::Krill> is a library to convert KorAP-XML documents to files
579compatible with the L<Krill|https://github.com/KorAP/Krill> indexer.
Akronf7ad89e2016-03-16 18:22:47 +0100580The C<korapxml2krill> command line tool is a simple wrapper to the library.
Akron941c1a62016-02-23 17:41:41 +0100581
582
583=head1 INSTALLATION
584
585The preferred way to install L<KorAP::XML::Krill> is to use L<cpanm|App::cpanminus>.
586
587 $ cpanm https://github.com/KorAP/KorAP-XML-Krill
588
Akronc13a1702016-03-15 19:33:14 +0100589In case everything went well, the C<korapxml2krill> tool will
Akronf7ad89e2016-03-16 18:22:47 +0100590be available on your command line immediately.
Akron941c1a62016-02-23 17:41:41 +0100591
592
593=head1 ARGUMENTS
594
595=over 2
596
597=item B<archive>
598
Akrone10ad322016-02-27 10:54:26 +0100599Process an archive as a Zip-file or a folder of KorAP-XML documents.
600
601=item B<extract>
602
603Extract KorAP-XML files from a Zip-file.
Akron941c1a62016-02-23 17:41:41 +0100604
605=back
606
607
608=head1 OPTIONS
609
610=over 2
611
Akron2cfe8092016-06-24 17:48:49 +0200612=item B<--input|-i> <directory|file|files>
Akron941c1a62016-02-23 17:41:41 +0100613
Akronf7ad89e2016-03-16 18:22:47 +0100614Directory or archive file of documents to convert.
Akron941c1a62016-02-23 17:41:41 +0100615
Akron0c3e3752016-06-28 15:55:53 +0200616Archiving supports multiple input archives with the constraint,
Akron2cfe8092016-06-24 17:48:49 +0200617that the first archive listed contains all primary data files
618and all meta data files.
Akron2cfe8092016-06-24 17:48:49 +0200619
620 -i file/news.zip -i file/news.malt.zip -i #file/news.tt.zip
621
Akron0c3e3752016-06-28 15:55:53 +0200622(The directory structure follows the base directory format,
623that may include a C<.> root folder.
624In this case further archives lacking a C<.> root folder
625need to be passed with a hash sign in front of the archive's name.)
Akron2cfe8092016-06-24 17:48:49 +0200626
Akron941c1a62016-02-23 17:41:41 +0100627=item B<--output|-o> <directory|file>
628
629Output folder for archive processing or
630document name for single output (optional),
Akronf7ad89e2016-03-16 18:22:47 +0100631writes to C<STDOUT> by default
632(in case C<output> is not mandatory due to further options).
Akron941c1a62016-02-23 17:41:41 +0100633
634=item B<--overwrite|-w>
635
636Overwrite files that already exist.
637
638=item B<--token|-t> <foundry>[#<file>]
639
640Define the default tokenization by specifying
641the name of the foundry and optionally the name
Akronc13a1702016-03-15 19:33:14 +0100642of the layer-file. Defaults to C<OpenNLP#tokens>.
Akron941c1a62016-02-23 17:41:41 +0100643
644=item B<--skip|-s> <foundry>[#<layer>]
645
Akronf7ad89e2016-03-16 18:22:47 +0100646Skip specific annotations by specifying the foundry
647(and optionally the layer with a C<#>-prefix),
648e.g. C<Mate> or C<Mate#Morpho>. Alternatively you can skip C<#ALL>.
Akron941c1a62016-02-23 17:41:41 +0100649Can be set multiple times.
650
Akronc13a1702016-03-15 19:33:14 +0100651=item B<--anno|-a> <foundry>#<layer>
Akron941c1a62016-02-23 17:41:41 +0100652
Akronf7ad89e2016-03-16 18:22:47 +0100653Convert specific annotations by specifying the foundry
654(and optionally the layer with a C<#>-prefix),
655e.g. C<Mate> or C<Mate#Morpho>.
656Can be set multiple times.
Akron941c1a62016-02-23 17:41:41 +0100657
658=item B<--primary|-p>
659
Akronc13a1702016-03-15 19:33:14 +0100660Output primary data or not. Defaults to C<true>.
Akronf7ad89e2016-03-16 18:22:47 +0100661Can be flagged using C<--no-primary> as well.
662This is I<deprecated>.
Akron941c1a62016-02-23 17:41:41 +0100663
664=item B<--jobs|-j>
665
666Define the number of concurrent jobs in seperated forks
Akronf7ad89e2016-03-16 18:22:47 +0100667for archive processing.
Akron11c80302016-03-18 19:44:43 +0100668Defaults to C<0> (everything runs in a single process).
Akronf7ad89e2016-03-16 18:22:47 +0100669This is I<experimental>.
Akron941c1a62016-02-23 17:41:41 +0100670
Akron35db6e32016-03-17 22:42:22 +0100671=item B<--meta|-m>
Akron941c1a62016-02-23 17:41:41 +0100672
Akron35db6e32016-03-17 22:42:22 +0100673Define the metadata parser to use. Defaults to C<I5>.
674Metadata parsers can be defined in the C<KorAP::XML::Meta> namespace.
675This is I<experimental>.
Akron941c1a62016-02-23 17:41:41 +0100676
677=item B<--pretty|-y>
678
Akronc13a1702016-03-15 19:33:14 +0100679Pretty print JSON output. Defaults to C<false>.
Akron35db6e32016-03-17 22:42:22 +0100680This is I<deprecated>.
Akron941c1a62016-02-23 17:41:41 +0100681
682=item B<--gzip|-z>
683
Akronf7ad89e2016-03-16 18:22:47 +0100684Compress the output.
685Expects a defined C<output> file in single processing.
Akron941c1a62016-02-23 17:41:41 +0100686
Akron11c80302016-03-18 19:44:43 +0100687=item B<--cache|-c>
688
689File to mmap a cache (using L<Cache::FastMmap>).
690Defaults to C<korapxml2krill.cache> in the calling directory.
691
692=item B<--cache-size|-cs>
693
694Size of the cache. Defaults to C<50m>.
695
696=item B<--cache-init|-ci>
697
698Initialize cache file.
699Can be flagged using C<--no-cache-init> as well.
700Defaults to C<true>.
701
702=item B<--cache-delete|-cd>
703
704Delete cache file after processing.
705Can be flagged using C<--no-cache-delete> as well.
706Defaults to C<true>.
707
Akrone10ad322016-02-27 10:54:26 +0100708=item B<--sigle|-sg>
709
710Extract the given text sigles.
Akrone10ad322016-02-27 10:54:26 +0100711Can be set multiple times.
Akronf7ad89e2016-03-16 18:22:47 +0100712I<Currently only supported on C<extract>.>
Akronb0c88db2016-06-29 16:33:18 +0200713Sigles have the structure C<Corpus>/C<Document>/C<Text>.
Akrone10ad322016-02-27 10:54:26 +0100714
Akron941c1a62016-02-23 17:41:41 +0100715=item B<--log|-l>
716
717The L<Log4perl> log level, defaults to C<ERROR>.
718
719=item B<--help|-h>
720
721Print this document.
722
723=item B<--version|-v>
724
725Print version information.
726
727=back
728
Akronc13a1702016-03-15 19:33:14 +0100729=head1 ANNOTATION SUPPORT
730
731L<KorAP::XML::Krill> has built-in importer for some annotation foundries and layers
732developed in the KorAP project that are part of the KorAP preprocessing pipeline.
733The base foundry with paragraphs, sentences, and the text element are mandatory for
734L<Krill|https://github.com/KorAP/Krill>.
735
Akronf7ad89e2016-03-16 18:22:47 +0100736=over 2
Akronc13a1702016-03-15 19:33:14 +0100737
738=item B<Base>
739
740=over 4
741
Akronf7ad89e2016-03-16 18:22:47 +0100742=item #Paragraphs
Akronc13a1702016-03-15 19:33:14 +0100743
Akronf7ad89e2016-03-16 18:22:47 +0100744=item #Sentences
Akronc13a1702016-03-15 19:33:14 +0100745
746=back
747
748=item B<Connexor>
749
750=over 4
751
Akronf7ad89e2016-03-16 18:22:47 +0100752=item #Morpho
Akronc13a1702016-03-15 19:33:14 +0100753
Akronf7ad89e2016-03-16 18:22:47 +0100754=item #Phrase
Akronc13a1702016-03-15 19:33:14 +0100755
Akronf7ad89e2016-03-16 18:22:47 +0100756=item #Sentences
Akronc13a1702016-03-15 19:33:14 +0100757
Akronf7ad89e2016-03-16 18:22:47 +0100758=item #Syntax
Akronc13a1702016-03-15 19:33:14 +0100759
760=back
761
762=item B<CoreNLP>
763
764=over 4
765
Akronf7ad89e2016-03-16 18:22:47 +0100766=item #Constituency
Akronc13a1702016-03-15 19:33:14 +0100767
Akronf7ad89e2016-03-16 18:22:47 +0100768=item #Morpho
Akronc13a1702016-03-15 19:33:14 +0100769
Akronf7ad89e2016-03-16 18:22:47 +0100770=item #NamedEntities
Akronc13a1702016-03-15 19:33:14 +0100771
Akronf7ad89e2016-03-16 18:22:47 +0100772=item #Sentences
Akronc13a1702016-03-15 19:33:14 +0100773
774=back
775
776=item B<DeReKo>
777
778=over 4
779
Akronf7ad89e2016-03-16 18:22:47 +0100780=item #Structure
Akronc13a1702016-03-15 19:33:14 +0100781
782=back
783
784=item B<Glemm>
785
786=over 4
787
Akronf7ad89e2016-03-16 18:22:47 +0100788=item #Morpho
Akronc13a1702016-03-15 19:33:14 +0100789
790=back
791
792=item B<Mate>
793
794=over 4
795
Akronf7ad89e2016-03-16 18:22:47 +0100796=item #Dependency
Akronc13a1702016-03-15 19:33:14 +0100797
Akronf7ad89e2016-03-16 18:22:47 +0100798=item #Morpho
Akronc13a1702016-03-15 19:33:14 +0100799
800=back
801
802=item B<OpenNLP>
803
804=over 4
805
Akronf7ad89e2016-03-16 18:22:47 +0100806=item #Morpho
Akronc13a1702016-03-15 19:33:14 +0100807
Akronf7ad89e2016-03-16 18:22:47 +0100808=item #Sentences
Akronc13a1702016-03-15 19:33:14 +0100809
810=back
811
812=item B<Sgbr>
813
814=over 4
815
Akronf7ad89e2016-03-16 18:22:47 +0100816=item #Lemma
Akronc13a1702016-03-15 19:33:14 +0100817
Akronf7ad89e2016-03-16 18:22:47 +0100818=item #Morpho
Akronc13a1702016-03-15 19:33:14 +0100819
820=back
821
822=item B<TreeTagger>
823
824=over 4
825
Akronf7ad89e2016-03-16 18:22:47 +0100826=item #Morpho
Akronc13a1702016-03-15 19:33:14 +0100827
Akronf7ad89e2016-03-16 18:22:47 +0100828=item #Sentences
Akronc13a1702016-03-15 19:33:14 +0100829
830=back
831
832=item B<XIP>
833
834=over 4
835
Akronf7ad89e2016-03-16 18:22:47 +0100836=item #Constituency
Akronc13a1702016-03-15 19:33:14 +0100837
Akronf7ad89e2016-03-16 18:22:47 +0100838=item #Morpho
Akronc13a1702016-03-15 19:33:14 +0100839
Akronf7ad89e2016-03-16 18:22:47 +0100840=item #Sentences
Akronc13a1702016-03-15 19:33:14 +0100841
842=back
843
844=back
845
846More importers are in preparation.
847New annotation importers can be defined in the C<KorAP::XML::Annotation> namespace.
848See the built-in annotation importers as examples.
849
Akron941c1a62016-02-23 17:41:41 +0100850=head1 AVAILABILITY
851
852 https://github.com/KorAP/KorAP-XML-Krill
853
854
855=head1 COPYRIGHT AND LICENSE
856
857Copyright (C) 2015-2016, L<IDS Mannheim|http://www.ids-mannheim.de/>
Akronf7ad89e2016-03-16 18:22:47 +0100858
Akron941c1a62016-02-23 17:41:41 +0100859Author: L<Nils Diewald|http://nils-diewald.de/>
860
861L<KorAP::XML::Krill> is developed as part of the L<KorAP|http://korap.ids-mannheim.de/>
862Corpus Analysis Platform at the
863L<Institute for the German Language (IDS)|http://ids-mannheim.de/>,
864member of the
865L<Leibniz-Gemeinschaft|http://www.leibniz-gemeinschaft.de/en/about-us/leibniz-competition/projekte-2011/2011-funding-line-2/>.
866
867This program is free software published under the
868L<BSD-2 License|https://raw.githubusercontent.com/KorAP/KorAP-XML-Krill/master/LICENSE>.
869
870=cut