/[webpac2]/trunk/run.pl
This is repository of my old source code which isn't updated any more. Go to git.rot13.org for current projects!
ViewVC logotype

Diff of /trunk/run.pl

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

revision 430 by dpavlin, Mon Apr 17 15:09:54 2006 UTC revision 706 by dpavlin, Mon Sep 25 14:06:49 2006 UTC
# Line 4  use strict; Line 4  use strict;
4    
5  use Cwd qw/abs_path/;  use Cwd qw/abs_path/;
6  use File::Temp qw/tempdir/;  use File::Temp qw/tempdir/;
 use Data::Dumper;  
7  use lib './lib';  use lib './lib';
8    
9  use WebPAC::Common 0.02;  use WebPAC::Common 0.02;
10  use WebPAC::Lookup;  use WebPAC::Parser 0.04;
11  use WebPAC::Input 0.03;  use WebPAC::Input 0.11;
12  use WebPAC::Store 0.03;  use WebPAC::Store 0.03;
13  use WebPAC::Normalize::XML;  use WebPAC::Normalize 0.11;
14  use WebPAC::Output::TT;  use WebPAC::Output::TT;
15  use YAML qw/LoadFile/;  use WebPAC::Validate 0.06;
16    use WebPAC::Output::MARC;
17    use WebPAC::Config;
18  use Getopt::Long;  use Getopt::Long;
19  use File::Path;  use File::Path;
20  use Time::HiRes qw/time/;  use Time::HiRes qw/time/;
21    use File::Slurp;
22    use Data::Dump qw/dump/;
23    use Storable qw/dclone/;
24    
25    use Proc::Queue size => 1;
26    use POSIX ":sys_wait_h"; # imports WNOHANG
27    
28  =head1 NAME  =head1 NAME
29    
# Line 40  limit loading to 100 records Line 47  limit loading to 100 records
47    
48  remove database and Hyper Estraier index before indexing  remove database and Hyper Estraier index before indexing
49    
50  =item --only=database_name  =item --only=database_name/input_filter
51    
52  reindex just single database (legacy name is --one)  reindex just single database (legacy name is --one)
53    
54    C</input_filter> is optional part which can be C<name>
55    or C<type> from input
56    
57  =item --config conf/config.yml  =item --config conf/config.yml
58    
59  path to YAML configuration file  path to YAML configuration file
60    
61    =item --stats
62    
63    disable indexing, modify_* in configuration and dump statistics about field
64    and subfield usage for each input
65    
66    =item --validate path/to/validation_file
67    
68    turn on extra validation of imput records, see L<WebPAC::Validation>
69    
70    =item --marc-normalize conf/normalize/mapping.pl
71    
72    This option specifies normalisation file for MARC creation
73    
74    =item --marc-output out/marc/test.marc
75    
76    Optional path to output file
77    
78    =item --marc-lint
79    
80    By default turned on if C<--marc-normalize> is used. You can disable lint
81    messages with C<--no-marc-lint>.
82    
83    =item --marc-dump
84    
85    Force dump or input and marc record for debugging.
86    
87    =item --parallel 4
88    
89    Run databases in parallel (aproximatly same as number of processors in
90    machine if you want to use full load)
91    
92    =item --only-links
93    
94    Create just links
95    
96    =item --merge
97    
98    Create merged index of databases which have links
99    
100  =back  =back
101    
102  =cut  =cut
# Line 56  my $offset; Line 105  my $offset;
105  my $limit;  my $limit;
106    
107  my $clean = 0;  my $clean = 0;
108  my $config = 'conf/config.yml';  my $config_path;
109  my $debug = 0;  my $debug = 0;
110  my $only_db_name;  my $only_filter;
111    my $stats = 0;
112    my $validate_path;
113    my ($marc_normalize, $marc_output);
114    my $marc_lint = 1;
115    my $marc_dump = 0;
116    my $parallel = 0;
117    my $only_links = 0;
118    my $merge = 0;
119    
120    my $log = _new WebPAC::Common()->_get_logger();
121    
122  GetOptions(  GetOptions(
123          "limit=i" => \$limit,          "limit=i" => \$limit,
124          "offset=i" => \$offset,          "offset=i" => \$offset,
125          "clean" => \$clean,          "clean" => \$clean,
126          "one=s" => \$only_db_name,          "one=s" => \$only_filter,
127          "only=s" => \$only_db_name,          "only=s" => \$only_filter,
128          "config" => \$config,          "config" => \$config_path,
129          "debug" => \$debug,          "debug+" => \$debug,
130            "stats" => \$stats,
131            "validate=s" => \$validate_path,
132            "marc-normalize=s" => \$marc_normalize,
133            "marc-output=s" => \$marc_output,
134            "marc-lint!" => \$marc_lint,
135            "marc-dump!" => \$marc_dump,
136            "parallel=i" => \$parallel,
137            "only-links!" => \$only_links,
138            "merge" => \$merge,
139  );  );
140    
141  $config = LoadFile($config);  my $config = new WebPAC::Config( path => $config_path );
142    
143    #print "config = ",dump($config) if ($debug);
144    
145    die "no databases in config file!\n" unless ($config->databases);
146    
147    $log->info( "-" x 79 );
148    
149    
150    my $estcmd_fh;
151    my $estcmd_path = './estcmd-merge.sh';
152    if ($merge) {
153            open($estcmd_fh, '>', $estcmd_path) || $log->logdie("can't open $estcmd_path: $!");
154            print $estcmd_fh 'cd /data/estraier/_node/ || exit 1',$/;
155            print $estcmd_fh 'sudo /etc/init.d/hyperestraier stop',$/;
156            $log->info("created merge batch file $estcmd_path");
157    }
158    
159    
160    my $validate;
161    $validate = new WebPAC::Validate(
162            path => $validate_path,
163    ) if ($validate_path);
164    
165    
166    my $use_indexer = $config->use_indexer;
167    if ($stats) {
168            $log->debug("option --stats disables update of indexing engine...");
169            $use_indexer = undef;
170    } else {
171            $log->info("using $use_indexer indexing engine...");
172    }
173    
174    # disable indexing when creating marc
175    $use_indexer = undef if ($marc_normalize);
176    
177  print "config = ",Dumper($config) if ($debug);  # parse normalize files and create source files for lookup and normalization
178    
179  die "no databases in config file!\n" unless ($config->{databases});  my $parser = new WebPAC::Parser( config => $config );
 my $use_indexer = $config->{use_indexer} || 'hyperestraier';  
180    
181  my $total_rows = 0;  my $total_rows = 0;
182  my $start_t = time();  my $start_t = time();
183    
184  while (my ($database, $db_config) = each %{ $config->{databases} }) {  my @links;
185    
186          next if ($only_db_name && $database !~ m/$only_db_name/i);  if ($parallel) {
187            $log->info("Using $parallel processes for speedup");
188            Proc::Queue::size($parallel);
189    }
190    
191    while (my ($database, $db_config) = each %{ $config->databases }) {
192    
193            my ($only_database,$only_input) = split(m#/#, $only_filter) if ($only_filter);
194            next if ($only_database && $database !~ m/$only_database/i);
195    
196          my $log = _new WebPAC::Common()->_get_logger();          if ($parallel) {
197                    my $f=fork;
198                    if(defined ($f) and $f==0) {
199                            $log->info("Created processes $$ for speedup");
200                    } else {
201                            next;
202                    }
203            }
204    
205          my $indexer;          my $indexer;
206            if ($use_indexer) {
207    
208          if ($use_indexer eq 'hyperestraier') {                  my $cfg_name = $use_indexer;
209                    $cfg_name =~ s/\-.*$//;
210    
211                  #                  my $indexer_config = $config->get( $cfg_name ) || $log->logdie("can't find '$cfg_name' part in confguration");
212                  # open Hyper Estraier database                  $indexer_config->{database} = $database;
213                  #                  $indexer_config->{clean} = $clean;
214                    $indexer_config->{label} = $db_config->{name};
                 use WebPAC::Output::Estraier '0.10';  
                 my $est_config = $config->{hyperestraier} || $log->logdie("can't find 'hyperestraier' part in confguration");  
                 $est_config->{database} = $database;  
                 $est_config->{clean} = $clean;  
                 $est_config->{label} = $db_config->{name};  
215    
216                  $indexer = new WebPAC::Output::Estraier( %{ $est_config } );                  # force clean if database has links
217          } else {                  $indexer_config->{clean} = 1 if ($db_config->{links});
218                  $log->logdie("unknown use_indexer: $use_indexer");  
219                    if ($use_indexer eq 'hyperestraier') {
220    
221                            # open Hyper Estraier database
222                            use WebPAC::Output::Estraier '0.10';
223                            $indexer = new WebPAC::Output::Estraier( %{ $indexer_config } );
224                    
225                    } elsif ($use_indexer eq 'hyperestraier-native') {
226    
227                            # open Hyper Estraier database
228                            use WebPAC::Output::EstraierNative;
229                            $indexer = new WebPAC::Output::EstraierNative( %{ $indexer_config } );
230    
231                    } elsif ($use_indexer eq 'kinosearch') {
232    
233                            # open KinoSearch
234                            use WebPAC::Output::KinoSearch;
235                            $indexer_config->{clean} = 1 unless (-e $indexer_config->{index_path});
236                            $indexer = new WebPAC::Output::KinoSearch( %{ $indexer_config } );
237    
238                    } else {
239                            $log->logdie("unknown use_indexer: $use_indexer");
240                    }
241    
242                    $log->logide("can't continue without valid indexer") unless ($indexer);
243          }          }
244    
245          $log->logide("can't continue without valid indexer") unless ($indexer);  
246            #
247            # store Hyper Estraier links to other databases
248            #
249            if (ref($db_config->{links}) eq 'ARRAY' && $use_indexer) {
250                    foreach my $link (@{ $db_config->{links} }) {
251                            if ($use_indexer eq 'hyperestraier') {
252                                    if ($merge) {
253                                            print $estcmd_fh 'sudo -u www-data estcmd merge ' . $database . ' ' . $link->{to},$/;
254                                    } else {
255                                            $log->info("saving link $database -> $link->{to} [$link->{credit}]");
256                                            push @links, sub {
257                                                    $log->info("adding link $database -> $link->{to} [$link->{credit}]");
258                                                    $indexer->add_link(
259                                                            from => $database,
260                                                            to => $link->{to},
261                                                            credit => $link->{credit},
262                                                    );
263                                            };
264                                    }
265                            } else {
266                                    $log->warn("NOT IMPLEMENTED WITH $use_indexer: adding link $database -> $link->{to} [$link->{credit}]");
267                            }
268                    }
269            }
270            next if ($only_links);
271    
272    
273          #          #
274          # now WebPAC::Store          # now WebPAC::Store
# Line 113  while (my ($database, $db_config) = each Line 276  while (my ($database, $db_config) = each
276          my $abs_path = abs_path($0);          my $abs_path = abs_path($0);
277          $abs_path =~ s#/[^/]*$#/#;          $abs_path =~ s#/[^/]*$#/#;
278    
279          my $db_path = $config->{webpac}->{db_path} . '/' . $database;          my $db_path = $config->get('webpac')->{db_path} . '/' . $database;
280    
281          if ($clean) {          if ($clean) {
282                  $log->info("creating new database $database in $db_path");                  $log->info("creating new database '$database' in $db_path");
283                  rmtree( $db_path ) || $log->warn("can't remove $db_path: $!");                  rmtree( $db_path ) || $log->warn("can't remove $db_path: $!");
284          } else {          } else {
285                  $log->debug("working on $database in $db_path");                  $log->info("working on database '$database' in $db_path");
286          }          }
287    
288          my $db = new WebPAC::Store(          my $db = new WebPAC::Store(
# Line 142  while (my ($database, $db_config) = each Line 305  while (my ($database, $db_config) = each
305                  $log->info("database $database doesn't have inputs defined");                  $log->info("database $database doesn't have inputs defined");
306          }          }
307    
         my @supported_inputs = keys %{ $config->{webpac}->{inputs} };  
   
308          foreach my $input (@inputs) {          foreach my $input (@inputs) {
309    
310                    next if ($only_input && ($input->{name} !~ m#$only_input#i && $input->{type} !~ m#$only_input#i));
311    
312                  my $type = lc($input->{type});                  my $type = lc($input->{type});
313    
314                  die "I know only how to handle input types ", join(",", @supported_inputs), " not '$type'!\n" unless (grep(/$type/, @supported_inputs));                  die "I know only how to handle input types ", join(",", $config->webpac('inputs') ), " not '$type'!\n" unless (grep(/$type/, $config->webpac('inputs')));
315    
316                  my $lookup = new WebPAC::Lookup(                  my $input_module = $config->webpac('inputs')->{$type};
317                          lookup_file => $input->{lookup},  
318                    my @lookups = $parser->have_lookup_create($database, $input);
319    
320                    $log->info("working on input '$input->{name}' in $input->{path} [type: $input->{type}] using $input_module",
321                            @lookups ? "lookup ".join(", ", @lookups) : ""
322                  );                  );
323    
324                  my $input_module = $config->{webpac}->{inputs}->{$type};  warn "lookups = ", dump( @lookups );
325    
326                  $log->info("working on input '$input->{path}' [$input->{type}] using $input_module lookup '$input->{lookup}'");                  if ($stats) {
327                            # disable modification of records if --stats is in use
328                            delete($input->{modify_records});
329                            delete($input->{modify_file});
330                    }
331    
332                    warn "parser->depends = ", dump( $parser->{depends} );
333                    warn "depends on: ", dump( $parser->depends($database, $input->{name}) );
334                    warn "lookup_create_rules = ", dump( $parser->lookup_create_rules($database, $input->{name}) );
335                    warn "parser->_lookup_create = ", dump( $parser->{_lookup_create} );
336    
337                    my $lookup;
338    
339                  my $input_db = new WebPAC::Input(                  my $input_db = new WebPAC::Input(
340                          module => $input_module,                          module => $input_module,
341                          code_page => $config->{webpac}->{webpac_encoding},                          encoding => $config->webpac('webpac_encoding'),
342                          limit => $limit || $input->{limit},                          limit => $limit || $input->{limit},
343                          offset => $offset,                          offset => $offset,
344                          lookup => $lookup,                          lookup_coderef => sub {
345                                    my $rec = shift || return;
346                                    $lookup->add( $rec );
347                            },
348                          recode => $input->{recode},                          recode => $input->{recode},
349                            stats => $stats,
350                            modify_records => $input->{modify_records},
351                            modify_file => $input->{modify_file},
352                  );                  );
353                  $log->logdie("can't create input using $input_module") unless ($input);                  $log->logdie("can't create input using $input_module") unless ($input);
354    
355                    if (defined( $input->{lookup} )) {
356                            $log->warn("$database/", $input->{name}, " has depriciated lookup definition, removing it...");
357                            delete( $input->{lookup} );
358                    }
359    
360                  my $maxmfn = $input_db->open(                  my $maxmfn = $input_db->open(
361                          path => $input->{path},                          path => $input->{path},
362                          code_page => $input->{encoding},        # database encoding                          code_page => $input->{encoding},        # database encoding
363                            %{ $input },
364                  );                  );
365    
366                  my $n = new WebPAC::Normalize::XML(                  my $report_fh;
367                  #       filter => { 'foo' => sub { shift } },                  if ($stats || $validate) {
368                          db => $db,                          my $path = "out/report/" . $database . '-' . $input->{name} . '.txt';
369                          lookup_regex => $lookup->regex,                          open($report_fh, '>', $path) || $log->logdie("can't open $path: $!");
370                          lookup => $lookup,  
371                          prefix => $input->{name},                          print $report_fh "Report for database '$database' input '$input->{name}' records ",
372                  );                                  $offset || 1, "-", $limit || $input->{limit} || $maxmfn, "\n\n";
373                            $log->info("Generating report file $path");
374                    }
375    
376                    my @norm_array = ref($input->{normalize}) eq 'ARRAY' ?
377                            @{ $input->{normalize} } : ( $input->{normalize} );
378    
379                    if ($marc_normalize) {
380                            @norm_array = ( {
381                                    path => $marc_normalize,
382                                    output => $marc_output || 'out/marc/' . $database . '-' . $input->{name} . '.marc',
383                            } );
384                    }
385    
386                    foreach my $normalize (@norm_array) {
387    
388                            my $normalize_path = $normalize->{path} || $log->logdie("can't find normalize path in config");
389    
390                            $log->logdie("Found '$normalize_path' as normalization file which isn't supported any more!") unless ( $normalize_path =~ m!\.pl$!i );
391    
392                            my $rules = read_file( $normalize_path ) or die "can't open $normalize_path: $!";
393    
394                            $log->info("Using $normalize_path for normalization...");
395    
396                            my $marc = new WebPAC::Output::MARC(
397                                    path => $normalize->{output},
398                                    lint => $marc_lint,
399                                    dump => $marc_dump,
400                            ) if ($normalize->{output});
401    
402                            # reset position in database
403                            $input_db->seek(1);
404    
405                            # generate name of config key for indexer (strip everything after -)
406                            my $indexer_config = $use_indexer;
407                            $indexer_config =~ s/^(\w+)-?.*$/$1/g if ($indexer_config);
408    
409                            foreach my $pos ( 0 ... $input_db->size ) {
410    
411                                    my $row = $input_db->fetch || next;
412    
413                  my $normalize_path = $input->{normalize}->{path};                                  my $mfn = $row->{'000'}->[0];
414    
415                  if ($normalize_path =~ m/\.xml$/i) {                                  if (! $mfn || $mfn !~ m#^\d+$#) {
416                          $n->open(                                          $log->warn("record $pos doesn't have valid MFN but '$mfn', using $pos");
417                                  tag => $input->{normalize}->{tag},                                          $mfn = $pos;
418                                  xml_file => $input->{normalize}->{path},                                          push @{ $row->{'000'} }, $pos;
419                          );                                  }
420                  } elsif ($normalize_path =~ m/\.(?:yml|yaml)$/i) {  
421                          $n->open_yaml(  
422                                  path => $normalize_path,                                  if ($validate) {
423                                  tag => $input->{normalize}->{tag},                                          if ( my $errors = $validate->validate_errors( $row, $input_db->dump ) ) {
424                          );                                                  $log->error( "MFN $mfn validation error:\n",
425                  }                                                          $validate->report_error( $errors )
426                                                    );
427                  foreach my $pos ( 0 ... $input_db->size ) {                                          }
428                                    }
429                          my $row = $input_db->fetch || next;  
430                                    my $ds_config = dclone($db_config);
431                          my $mfn = $row->{'000'}->[0];  
432                                    # default values -> database key
433                          if (! $mfn || $mfn !~ m#^\d+$#) {                                  $ds_config->{_} = $database;
434                                  $log->warn("record $pos doesn't have valid MFN but '$mfn', using $pos");  
435                                  $mfn = $pos;                                  # current mfn
436                                  push @{ $row->{'000'} }, $pos;                                  $ds_config->{_mfn} = $mfn;
437    
438                                    # attach current input
439                                    $ds_config->{input} = $input;
440    
441                                    my $ds = WebPAC::Normalize::data_structure(
442                                            row => $row,
443                                            rules => $rules,
444                                            lookup => $lookup ? $lookup->lookup_hash : undef,
445                                            config => $ds_config,
446                                            marc_encoding => 'utf-8',
447                                    );
448    
449                                    $db->save_ds(
450                                            id => $mfn,
451                                            ds => $ds,
452                                            prefix => $input->{name},
453                                    ) if ($ds && !$stats);
454    
455                                    $indexer->add(
456                                            id => $input->{name} . "/" . $mfn,
457                                            ds => $ds,
458                                            type => $config->get($indexer_config)->{type},
459                                    ) if ($indexer && $ds);
460    
461                                    if ($marc) {
462                                            my $i = 0;
463    
464                                            while (my $fields = WebPAC::Normalize::_get_marc_fields( fetch_next => 1 ) ) {
465                                                    $marc->add(
466                                                            id => $mfn . ( $i ? "/$i" : '' ),
467                                                            fields => $fields,
468                                                            leader => WebPAC::Normalize::marc_leader(),
469                                                            row => $row,
470                                                    );
471                                                    $i++;
472                                            }
473    
474                                            $log->info("Created $i instances of MFN $mfn\n") if ($i > 1);
475                                    }
476    
477                                    $total_rows++;
478                          }                          }
479    
480                          my $ds = $n->data_structure($row);                          if ($validate) {
481                                    my $errors = $validate->report;
482                                    if ($errors) {
483                                            $log->info("validation errors:\n$errors\n" );
484                                            print $report_fh "$errors\n" if ($report_fh);
485                                    }
486                            }
487    
488                          $indexer->add(                          if ($stats) {
489                                  id => $input->{name} . "/" . $mfn,                                  my $s = $input_db->stats;
490                                  ds => $ds,                                  $log->info("statistics of fields usage:\n$s");
491                                  type => $config->{$use_indexer}->{type},                                  print $report_fh "Statistics of fields usage:\n$s" if ($report_fh);
492                          );                          }
493    
494                          $total_rows++;                          # close MARC file
495                            $marc->finish if ($marc);
496    
497                            # close report
498                            close($report_fh) if ($report_fh)
499                  }                  }
500    
501          };          }
502    
503            eval { $indexer->finish } if ($indexer && $indexer->can('finish'));
504    
505          my $dt = time() - $start_t;          my $dt = time() - $start_t;
506          $log->info("$total_rows records indexed in " .          $log->info("$total_rows records ", $indexer ? "indexed " : "",
507                  sprintf("%.2f sec [%.2f rec/sec]",                  sprintf("in %.2f sec [%.2f rec/sec]",
508                          $dt, ($total_rows / $dt)                          $dt, ($total_rows / $dt)
509                  )                  )
510          );          );
511    
512          if ($use_indexer eq 'hyperestraier') {  
513                  #          # end forked process
514                  # add Hyper Estraier links to other databases          if ($parallel) {
515                  #                  $log->info("parallel process $$ finished");
516                  if (ref($db_config->{links}) eq 'ARRAY') {                  exit(0);
                         foreach my $link (@{ $db_config->{links} }) {  
                                 $log->info("adding link $database -> $link->{to} [$link->{credit}]");  
                                 $indexer->add_link(  
                                         from => $database,  
                                         to => $link->{to},  
                                         credit => $link->{credit},  
                                 );  
                         }  
                 }  
         } else {  
                 $log->warn("links not implemented for $use_indexer");  
517          }          }
518    
519  }  }
520    
521    if ($parallel) {
522            # wait all children to finish
523            sleep(1) while wait != -1;
524            $log->info("all parallel processes finished");
525    }
526    
527    #
528    # handle links or merge after indexing
529    #
530    
531    if ($merge) {
532            print $estcmd_fh 'sudo /etc/init.d/hyperestraier start',$/;
533            close($estcmd_fh);
534            chmod 0700, $estcmd_path || $log->warn("can't chmod 0700 $estcmd_path: $!");
535            system $estcmd_path;
536    } else {
537            foreach my $link (@links) {
538                    $log->logdie("coderef in link ", Dumper($link), " is ", ref($link), " and not CODE") unless (ref($link) eq 'CODE');
539                    $link->();
540            }
541    }

Legend:
Removed from v.430  
changed lines
  Added in v.706

  ViewVC Help
Powered by ViewVC 1.1.26