/[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 301 by dpavlin, Mon Dec 19 21:26:04 2005 UTC revision 736 by dpavlin, Thu Oct 5 12:57:51 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.13;
12  use WebPAC::Store 0.03;  use WebPAC::Store 0.11;
13  use WebPAC::Normalize::XML;  use WebPAC::Normalize 0.22;
14  use WebPAC::Output::TT;  use WebPAC::Output::TT;
15  use WebPAC::Output::Estraier 0.05;  use WebPAC::Validate 0.06;
16  use YAML qw/LoadFile/;  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/;
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/input_filter
51    
52    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 52  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_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          "config" => \$config,          "one=s" => \$only_filter,
127          "debug" => \$debug,          "only=s" => \$only_filter,
128            "config" => \$config_path,
129            "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  print "config = ",Dumper($config) if ($debug);  $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  die "no databases in config file!\n" unless ($config->{databases});  # disable indexing when creating marc
175    $use_indexer = undef if ($marc_normalize);
176    
177    # parse normalize files and create source files for lookup and normalization
178    
179    my $parser = new WebPAC::Parser( config => $config );
180    
181  my $total_rows = 0;  my $total_rows = 0;
182    my $start_t = time();
183    
184  while (my ($database, $db_config) = each %{ $config->{databases} }) {  my @links;
185    
186          my $log = _new WebPAC::Common()->_get_logger();  if ($parallel) {
187            $log->info("Using $parallel processes for speedup");
188            Proc::Queue::size($parallel);
189    }
190    
191          #  sub create_ds_config {
192          # open Hyper Estraier database          my ($db_config, $database, $input, $mfn) = @_;
193          #          my $c = dclone( $db_config );
194            $c->{_} = $database || $log->logconfess("need database");
195            $c->{_mfn} = $mfn || $log->logconfess("need mfn");
196            $c->{input} = $input || $log->logconfess("need input");
197            return $c;
198    }
199    
200          my $est_config = $config->{hyperestraier} || $log->logdie("can't find 'hyperestraier' part in confguration");  while (my ($database, $db_config) = each %{ $config->databases }) {
         $est_config->{database} = $database;  
201    
202          my $est = new WebPAC::Output::Estraier(          my ($only_database,$only_input) = split(m#/#, $only_filter) if ($only_filter);
203                  %{ $est_config },          next if ($only_database && $database !~ m/$only_database/i);
         );  
204    
205          if ($clean) {          if ($parallel) {
206                  $log->warn("creating new empty index $database");                  my $f=fork;
207                  $est->master( action => 'nodedel', name => $database );                  if(defined ($f) and $f==0) {
208                  $est->master( action => 'nodeadd', name => $database, label => $database );                          $log->info("Created processes $$ for speedup");
209                    } else {
210                            next;
211                    }
212            }
213    
214            my $indexer;
215            if ($use_indexer) {
216    
217                    my $cfg_name = $use_indexer;
218                    $cfg_name =~ s/\-.*$//;
219    
220                    my $indexer_config = $config->get( $cfg_name ) || $log->logdie("can't find '$cfg_name' part in confguration");
221                    $indexer_config->{database} = $database;
222                    $indexer_config->{clean} = $clean;
223                    $indexer_config->{label} = $db_config->{name};
224    
225                    # force clean if database has links
226                    $indexer_config->{clean} = 1 if ($db_config->{links});
227    
228                    if ($use_indexer eq 'hyperestraier') {
229    
230                            # open Hyper Estraier database
231                            use WebPAC::Output::Estraier '0.10';
232                            $indexer = new WebPAC::Output::Estraier( %{ $indexer_config } );
233                    
234                    } elsif ($use_indexer eq 'hyperestraier-native') {
235    
236                            # open Hyper Estraier database
237                            use WebPAC::Output::EstraierNative;
238                            $indexer = new WebPAC::Output::EstraierNative( %{ $indexer_config } );
239    
240                    } elsif ($use_indexer eq 'kinosearch') {
241    
242                            # open KinoSearch
243                            use WebPAC::Output::KinoSearch;
244                            $indexer_config->{clean} = 1 unless (-e $indexer_config->{index_path});
245                            $indexer = new WebPAC::Output::KinoSearch( %{ $indexer_config } );
246    
247                    } else {
248                            $log->logdie("unknown use_indexer: $use_indexer");
249                    }
250    
251                    $log->logide("can't continue without valid indexer") unless ($indexer);
252            }
253    
254    
255            #
256            # store Hyper Estraier links to other databases
257            #
258            if (ref($db_config->{links}) eq 'ARRAY' && $use_indexer) {
259                    foreach my $link (@{ $db_config->{links} }) {
260                            if ($use_indexer eq 'hyperestraier') {
261                                    if ($merge) {
262                                            print $estcmd_fh 'sudo -u www-data estcmd merge ' . $database . ' ' . $link->{to},$/;
263                                    } else {
264                                            $log->info("saving link $database -> $link->{to} [$link->{credit}]");
265                                            push @links, sub {
266                                                    $log->info("adding link $database -> $link->{to} [$link->{credit}]");
267                                                    $indexer->add_link(
268                                                            from => $database,
269                                                            to => $link->{to},
270                                                            credit => $link->{credit},
271                                                    );
272                                            };
273                                    }
274                            } else {
275                                    $log->warn("NOT IMPLEMENTED WITH $use_indexer: adding link $database -> $link->{to} [$link->{credit}]");
276                            }
277                    }
278          }          }
279            next if ($only_links);
280    
281    
282          #          #
283          # now WebPAC::Store          # now WebPAC::Store
# Line 98  while (my ($database, $db_config) = each Line 285  while (my ($database, $db_config) = each
285          my $abs_path = abs_path($0);          my $abs_path = abs_path($0);
286          $abs_path =~ s#/[^/]*$#/#;          $abs_path =~ s#/[^/]*$#/#;
287    
288          my $db_path = $config->{webpac}->{db_path} . '/' . $database;          my $db_path = $config->webpac('db_path');
289    
290          if ($clean) {          if ($clean) {
291                  $log->info("creating new database $database in $db_path");                  $log->info("creating new database '$database' in $db_path");
292                  rmtree( $db_path ) || $log->warn("can't remove $db_path: $!");                  rmtree( $db_path ) || $log->warn("can't remove $db_path: $!");
293          } else {          } else {
294                  $log->info("working on $database in $db_path");                  $log->info("working on database '$database' in $db_path");
295          }          }
296    
297          my $db = new WebPAC::Store(          my $store = new WebPAC::Store(
298                  path => $db_path,                  path => $db_path,
                 database => $database,  
299                  debug => $debug,                  debug => $debug,
300          );          );
301    
# Line 127  while (my ($database, $db_config) = each Line 313  while (my ($database, $db_config) = each
313                  $log->info("database $database doesn't have inputs defined");                  $log->info("database $database doesn't have inputs defined");
314          }          }
315    
         my @supported_inputs = keys %{ $config->{webpac}->{inputs} };  
   
316          foreach my $input (@inputs) {          foreach my $input (@inputs) {
317    
318                    my $input_name = $input->{name} || $log->logdie("input without a name isn't valid: ",dump($input));
319    
320                    next if ($only_input && ($input_name !~ m#$only_input#i && $input->{type} !~ m#$only_input#i));
321    
322                  my $type = lc($input->{type});                  my $type = lc($input->{type});
323    
324                  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')));
325    
326                  my $lookup = new WebPAC::Lookup(                  my $input_module = $config->webpac('inputs')->{$type};
                         lookup_file => $input->{lookup},  
                 );  
327    
328                  my $input_module = $config->{webpac}->{inputs}->{$type};                  my @lookups = $parser->have_lookup_create($database, $input);
329    
330                  $log->info("working on input $input->{path} [$input->{type}] using $input_module");                  $log->info("working on input '$input_name' in $input->{path} [type: $input->{type}] using $input_module",
331                            @lookups ? " creating lookups: ".join(", ", @lookups) : ""
332                    );
333    
334                    if ($stats) {
335                            # disable modification of records if --stats is in use
336                            delete($input->{modify_records});
337                            delete($input->{modify_file});
338                    }
339    
340                  my $input_db = new WebPAC::Input(                  my $input_db = new WebPAC::Input(
341                          module => $input_module,                          module => $input_module,
342                          code_page => $config->{webpac}->{webpac_encoding},                          encoding => $config->webpac('webpac_encoding'),
343                          limit => $limit || $input->{limit},                          limit => $limit || $input->{limit},
344                          offset => $offset,                          offset => $offset,
345                          lookup => $lookup,                          recode => $input->{recode},
346                            stats => $stats,
347                            modify_records => $input->{modify_records},
348                            modify_file => $input->{modify_file},
349                  );                  );
350                  $log->logdie("can't create input using $input_module") unless ($input);                  $log->logdie("can't create input using $input_module") unless ($input);
351    
352                    if (defined( $input->{lookup} )) {
353                            $log->warn("$database/$input_name has depriciated lookup definition, removing it...");
354                            delete( $input->{lookup} );
355                    }
356    
357                    my $lookup_coderef;
358    
359                    if (@lookups) {
360    
361                            my $rules = $parser->lookup_create_rules($database, $input) || $log->logdie("no rules found for $database/$input");
362    
363                            $lookup_coderef = sub {
364                                    my $rec = shift || die "need rec!";
365                                    my $mfn = $rec->{'000'}->[0] || die "need mfn in 000";
366    
367                                    $store->save_row(
368                                            database => $database,
369                                            input => $input_name,
370                                            id => $mfn,
371                                            row => $rec,
372                                    );
373    
374                                    WebPAC::Normalize::data_structure(
375                                            row => $rec,
376                                            rules => $rules,
377                                            config => create_ds_config( $db_config, $database, $input, $mfn ),
378                                    );
379    
380                                    #warn "current lookup: ", dump(WebPAC::Normalize::_get_lookup());
381                            };
382    
383                            WebPAC::Normalize::_set_lookup( undef );
384    
385                            $log->debug("created lookup_coderef using:\n$rules");
386    
387                    };
388    
389                    my $lookup_jar;
390    
391                  my $maxmfn = $input_db->open(                  my $maxmfn = $input_db->open(
392                          path => $input->{path},                          path => $input->{path},
393                          code_page => $input->{encoding},        # database encoding                          code_page => $input->{encoding},        # database encoding
394                            lookup_coderef => $lookup_coderef,
395                            lookup => $lookup_jar,
396                            %{ $input },
397                  );                  );
398    
399                  my $n = new WebPAC::Normalize::XML(                  my $lookup_data = WebPAC::Normalize::_get_lookup();
                 #       filter => { 'foo' => sub { shift } },  
                         db => $db,  
                         lookup_regex => $lookup->regex,  
                         lookup => $lookup,  
                         prefix => $input->{name},  
                 );  
400    
401                  my $normalize_path = $input->{normalize}->{path};                  if (defined( $lookup_data->{$database}->{$input_name} )) {
402                            $log->debug("created following lookups: ", dump( $lookup_data ));
403    
404                  if ($normalize_path =~ m/\.xml$/i) {                          foreach my $key (keys %{ $lookup_data->{$database}->{$input_name} }) {
405                          $n->open(                                  $store->save_lookup(
406                                  tag => $input->{normalize}->{tag},                                          database => $database,
407                                  xml_file => $input->{normalize}->{path},                                          input => $input_name,
408                          );                                          key => $key,
409                  } elsif ($normalize_path =~ m/\.(?:yml|yaml)$/i) {                                          data => $lookup_data->{$database}->{$input_name}->{$key},
410                          $n->open_yaml(                                  );
411                                  path => $normalize_path,                          }
412                                  tag => $input->{normalize}->{tag},                  }
413    
414                    my $report_fh;
415                    if ($stats || $validate) {
416                            my $path = "out/report/${database}-${input_name}.txt";
417                            open($report_fh, '>', $path) || $log->logdie("can't open $path: $!");
418    
419                            print $report_fh "Report for database '$database' input '$input_name' records ",
420                                    $offset || 1, "-", $limit || $input->{limit} || $maxmfn, "\n\n";
421                            $log->info("Generating report file $path");
422                    }
423    
424                    my $marc;
425                    if ($marc_normalize) {
426                            $marc = new WebPAC::Output::MARC(
427                                    path => $marc_output || "out/marc/${database}-${input_name}.marc",
428                                    lint => $marc_lint,
429                                    dump => $marc_dump,
430                          );                          );
431                  }                  }
432    
433                    my $rules = $parser->normalize_rules($database,$input_name) || $log->logdie("no normalize rules found for $database/$input_name");
434                    $log->debug("parsed normalize rules:\n$rules");
435    
436                    # reset position in database
437                    $input_db->seek(1);
438    
439                    # generate name of config key for indexer (strip everything after -)
440                    my $indexer_config = $use_indexer;
441                    $indexer_config =~ s/^(\w+)-?.*$/$1/g if ($indexer_config);
442    
443                    my $lookup_hash;
444                    my $depends = $parser->depends($database,$input_name);
445            
446                    if ($depends) {
447                            $log->debug("$database/$input_name depends on: ", dump($depends)) if ($depends);
448                            $log->logdie("parser->depends didn't return HASH") unless (ref($depends) eq 'HASH');
449    
450                            foreach my $db (keys %$depends) {
451                                    foreach my $i (keys %{$depends->{$db}}) {
452                                            foreach my $k (keys %{$depends->{$db}->{$i}}) {
453                                                    $log->debug("loading lookup $db/$i");
454                                                    $lookup_hash->{$db}->{$i}->{$k} = $store->load_lookup(
455                                                            database => $db,
456                                                            input => $i,
457                                                            key => $k,
458                                                    );
459                                            }
460                                    }
461                            }
462    
463                            $log->debug("lookup_hash = ", dump( $lookup_hash ));
464                    }
465    
466    
467                  foreach my $pos ( 0 ... $input_db->size ) {                  foreach my $pos ( 0 ... $input_db->size ) {
468    
469                          my $row = $input_db->fetch || next;                          my $row = $input_db->fetch || next;
# Line 191  while (my ($database, $db_config) = each Line 476  while (my ($database, $db_config) = each
476                                  push @{ $row->{'000'} }, $pos;                                  push @{ $row->{'000'} }, $pos;
477                          }                          }
478    
                         my $ds = $n->data_structure($row);  
479    
480                          $est->add(                          if ($validate) {
481                                  id => $input->{name} . "/" . $mfn,                                  if ( my $errors = $validate->validate_errors( $row, $input_db->dump ) ) {
482                                  ds => $ds,                                          $log->error( "MFN $mfn validation error:\n",
483                                  type => $config->{hyperestraier}->{type},                                                  $validate->report_error( $errors )
484                                            );
485                                    }
486                            }
487    
488                            my $ds = WebPAC::Normalize::data_structure(
489                                    row => $row,
490                                    rules => $rules,
491                                    lookup => $lookup_hash,
492                                    config => create_ds_config( $db_config, $database, $input, $mfn ),
493                                    marc_encoding => 'utf-8',
494                                    load_row_coderef => sub {
495                                            my ($database,$input,$mfn) = @_;
496                                            return $store->load_row(
497                                                    database => $database,
498                                                    input => $input,
499                                                    id => $mfn,
500                                            );
501                                    },
502                          );                          );
503    
504                            $log->debug("ds = ",dump($ds));
505    
506                            $store->save_ds(
507                                    database => $database,
508                                    input => $input_name,
509                                    id => $mfn,
510                                    ds => $ds,
511                            ) if ($ds && !$stats);
512    
513                            $indexer->add(
514                                    id => "${input_name}/${mfn}",
515                                    ds => $ds,
516                                    type => $config->get($indexer_config)->{type},
517                            ) if ($indexer && $ds);
518    
519                            if ($marc) {
520                                    my $i = 0;
521    
522                                    while (my $fields = WebPAC::Normalize::_get_marc_fields( fetch_next => 1 ) ) {
523                                            $marc->add(
524                                                    id => $mfn . ( $i ? "/$i" : '' ),
525                                                    fields => $fields,
526                                                    leader => WebPAC::Normalize::marc_leader(),
527                                                    row => $row,
528                                            );
529                                            $i++;
530                                    }
531    
532                                    $log->info("Created $i instances of MFN $mfn\n") if ($i > 1);
533                            }
534    
535                          $total_rows++;                          $total_rows++;
536                  }                  }
537    
538          };                  if ($validate) {
539                            my $errors = $validate->report;
540          $log->info("$total_rows records indexed");                          if ($errors) {
541                                    $log->info("validation errors:\n$errors\n" );
542                                    print $report_fh "$errors\n" if ($report_fh);
543                            }
544                    }
545    
546          #                  if ($stats) {
547          # add Hyper Estraier links to other databases                          my $s = $input_db->stats;
548          #                          $log->info("statistics of fields usage:\n$s");
549          if (ref($db_config->{links}) eq 'ARRAY') {                          print $report_fh "Statistics of fields usage:\n$s" if ($report_fh);
                 foreach my $link (@{ $db_config->{links} }) {  
                         $log->info("adding link $database -> $link->{to} [$link->{credit}]");  
                         $est->add_link(  
                                 from => $database,  
                                 to => $link->{to},  
                                 credit => $link->{credit},  
                         );  
550                  }                  }
551    
552                    # close MARC file
553                    $marc->finish if ($marc);
554    
555                    # close report
556                    close($report_fh) if ($report_fh)
557    
558            }
559    
560            eval { $indexer->finish } if ($indexer && $indexer->can('finish'));
561    
562            my $dt = time() - $start_t;
563            $log->info("$total_rows records ", $indexer ? "indexed " : "",
564                    sprintf("in %.2f sec [%.2f rec/sec]",
565                            $dt, ($total_rows / $dt)
566                    )
567            );
568    
569    
570            # end forked process
571            if ($parallel) {
572                    $log->info("parallel process $$ finished");
573                    exit(0);
574          }          }
575    
576  }  }
577    
578    if ($parallel) {
579            # wait all children to finish
580            sleep(1) while wait != -1;
581            $log->info("all parallel processes finished");
582    }
583    
584    #
585    # handle links or merge after indexing
586    #
587    
588    if ($merge) {
589            print $estcmd_fh 'sudo /etc/init.d/hyperestraier start',$/;
590            close($estcmd_fh);
591            chmod 0700, $estcmd_path || $log->warn("can't chmod 0700 $estcmd_path: $!");
592            system $estcmd_path;
593    } else {
594            foreach my $link (@links) {
595                    $log->logdie("coderef in link ", Dumper($link), " is ", ref($link), " and not CODE") unless (ref($link) eq 'CODE');
596                    $link->();
597            }
598    }

Legend:
Removed from v.301  
changed lines
  Added in v.736

  ViewVC Help
Powered by ViewVC 1.1.26