/[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 416 by dpavlin, Sun Feb 26 23:21:50 2006 UTC revision 707 by dpavlin, Mon Sep 25 15:26:12 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.03;
13  use WebPAC::Normalize::XML;  use WebPAC::Normalize 0.11;
14  use WebPAC::Output::TT;  use WebPAC::Output::TT;
15  use WebPAC::Output::Estraier '0.10';  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/;  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 41  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 --one=database_name  =item --only=database_name/input_filter
51    
52    reindex just single database (legacy name is --one)
53    
54  reindex just single database  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 57  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 $one_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" => \$one_db_name,          "one=s" => \$only_filter,
127          "config" => \$config,          "only=s" => \$only_filter,
128          "debug" => \$debug,          "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  die "no databases in config file!\n" unless ($config->{databases});  
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    # 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();  my $start_t = time();
183    
184  while (my ($database, $db_config) = each %{ $config->{databases} }) {  my @links;
185    
186          next if ($one_db_name && $database !~ m/$one_db_name/i);  if ($parallel) {
187            $log->info("Using $parallel processes for speedup");
188            Proc::Queue::size($parallel);
189    }
190    
191    sub create_ds_config {
192            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    while (my ($database, $db_config) = each %{ $config->databases }) {
201    
202            my ($only_database,$only_input) = split(m#/#, $only_filter) if ($only_filter);
203            next if ($only_database && $database !~ m/$only_database/i);
204    
205            if ($parallel) {
206                    my $f=fork;
207                    if(defined ($f) and $f==0) {
208                            $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    
         my $log = _new WebPAC::Common()->_get_logger();  
254    
255          #          #
256          # open Hyper Estraier database          # 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    
         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};  
   
         my $est = new WebPAC::Output::Estraier( %{ $est_config } );  
281    
282          #          #
283          # now WebPAC::Store          # now WebPAC::Store
# Line 102  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->get('webpac')->{db_path} . '/' . $database;
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->debug("working on $database in $db_path");                  $log->info("working on database '$database' in $db_path");
295          }          }
296    
297          my $db = new WebPAC::Store(          my $db = new WebPAC::Store(
# Line 131  while (my ($database, $db_config) = each Line 314  while (my ($database, $db_config) = each
314                  $log->info("database $database doesn't have inputs defined");                  $log->info("database $database doesn't have inputs defined");
315          }          }
316    
         my @supported_inputs = keys %{ $config->{webpac}->{inputs} };  
   
317          foreach my $input (@inputs) {          foreach my $input (@inputs) {
318    
319                    next if ($only_input && ($input->{name} !~ m#$only_input#i && $input->{type} !~ m#$only_input#i));
320    
321                  my $type = lc($input->{type});                  my $type = lc($input->{type});
322    
323                  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')));
324    
325                  my $lookup = new WebPAC::Lookup(                  my $input_module = $config->webpac('inputs')->{$type};
                         lookup_file => $input->{lookup},  
                 );  
326    
327                  my $input_module = $config->{webpac}->{inputs}->{$type};                  my @lookups = $parser->have_lookup_create($database, $input);
328    
329                  $log->info("working on input '$input->{path}' [$input->{type}] using $input_module lookup '$input->{lookup}'");                  $log->info("working on input '$input->{name}' in $input->{path} [type: $input->{type}] using $input_module",
330                            @lookups ? " creating lookups: ".join(", ", @lookups) : ""
331                    );
332    
333                    if ($stats) {
334                            # disable modification of records if --stats is in use
335                            delete($input->{modify_records});
336                            delete($input->{modify_file});
337                    }
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,
                         lookup => $lookup,  
344                          recode => $input->{recode},                          recode => $input->{recode},
345                            stats => $stats,
346                            modify_records => $input->{modify_records},
347                            modify_file => $input->{modify_file},
348                  );                  );
349                  $log->logdie("can't create input using $input_module") unless ($input);                  $log->logdie("can't create input using $input_module") unless ($input);
350    
351                    if (defined( $input->{lookup} )) {
352                            $log->warn("$database/", $input->{name}, " has depriciated lookup definition, removing it...");
353                            delete( $input->{lookup} );
354                    }
355    
356                    my $lookup;
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                                    WebPAC::Normalize::data_structure(
368                                            row => $rec,
369                                            rules => $rules,
370                                            lookup => $lookup,
371                                            config => create_ds_config( $db_config, $database, $input, $mfn ),
372                                    );
373    
374                                    warn "current lookup = ", dump($lookup) if ($lookup);
375                            };
376    
377                            WebPAC::Normalize::_set_lookup( undef );
378    
379                            $log->debug("created lookup_coderef using:\n$rules");
380    
381                    };
382    
383                  my $maxmfn = $input_db->open(                  my $maxmfn = $input_db->open(
384                          path => $input->{path},                          path => $input->{path},
385                          code_page => $input->{encoding},        # database encoding                          code_page => $input->{encoding},        # database encoding
386                            lookup_coderef => $lookup_coderef,
387                            %{ $input },
388                  );                  );
389    
390                  my $n = new WebPAC::Normalize::XML(                  $log->debug("created following lookups: ", dump( WebPAC::Normalize::_get_lookup() ) );
391                  #       filter => { 'foo' => sub { shift } },  
392                          db => $db,                  my $report_fh;
393                          lookup_regex => $lookup->regex,                  if ($stats || $validate) {
394                          lookup => $lookup,                          my $path = "out/report/" . $database . '-' . $input->{name} . '.txt';
395                          prefix => $input->{name},                          open($report_fh, '>', $path) || $log->logdie("can't open $path: $!");
396                  );  
397                            print $report_fh "Report for database '$database' input '$input->{name}' records ",
398                                    $offset || 1, "-", $limit || $input->{limit} || $maxmfn, "\n\n";
399                            $log->info("Generating report file $path");
400                    }
401    
402                    my @norm_array = ref($input->{normalize}) eq 'ARRAY' ?
403                            @{ $input->{normalize} } : ( $input->{normalize} );
404    
405                    if ($marc_normalize) {
406                            @norm_array = ( {
407                                    path => $marc_normalize,
408                                    output => $marc_output || 'out/marc/' . $database . '-' . $input->{name} . '.marc',
409                            } );
410                    }
411    
412                    foreach my $normalize (@norm_array) {
413    
414                  my $normalize_path = $input->{normalize}->{path};                          my $normalize_path = $normalize->{path} || $log->logdie("can't find normalize path in config");
415    
416                  if ($normalize_path =~ m/\.xml$/i) {                          $log->logdie("Found '$normalize_path' as normalization file which isn't supported any more!") unless ( $normalize_path =~ m!\.pl$!i );
417                          $n->open(  
418                                  tag => $input->{normalize}->{tag},                          my $rules = read_file( $normalize_path ) or die "can't open $normalize_path: $!";
419                                  xml_file => $input->{normalize}->{path},  
420                          );                          $log->info("Using $normalize_path for normalization...");
421                  } elsif ($normalize_path =~ m/\.(?:yml|yaml)$/i) {  
422                          $n->open_yaml(                          my $marc = new WebPAC::Output::MARC(
423                                  path => $normalize_path,                                  path => $normalize->{output},
424                                  tag => $input->{normalize}->{tag},                                  lint => $marc_lint,
425                          );                                  dump => $marc_dump,
426                  }                          ) if ($normalize->{output});
427    
428                  foreach my $pos ( 0 ... $input_db->size ) {                          # reset position in database
429                            $input_db->seek(1);
430                          my $row = $input_db->fetch || next;  
431                            # generate name of config key for indexer (strip everything after -)
432                          my $mfn = $row->{'000'}->[0];                          my $indexer_config = $use_indexer;
433                            $indexer_config =~ s/^(\w+)-?.*$/$1/g if ($indexer_config);
434                          if (! $mfn || $mfn !~ m#^\d+$#) {  
435                                  $log->warn("record $pos doesn't have valid MFN but '$mfn', using $pos");                          foreach my $pos ( 0 ... $input_db->size ) {
436                                  $mfn = $pos;  
437                                  push @{ $row->{'000'} }, $pos;                                  my $row = $input_db->fetch || next;
438    
439                                    my $mfn = $row->{'000'}->[0];
440    
441                                    if (! $mfn || $mfn !~ m#^\d+$#) {
442                                            $log->warn("record $pos doesn't have valid MFN but '$mfn', using $pos");
443                                            $mfn = $pos;
444                                            push @{ $row->{'000'} }, $pos;
445                                    }
446    
447    
448                                    if ($validate) {
449                                            if ( my $errors = $validate->validate_errors( $row, $input_db->dump ) ) {
450                                                    $log->error( "MFN $mfn validation error:\n",
451                                                            $validate->report_error( $errors )
452                                                    );
453                                            }
454                                    }
455    
456                                    my $ds = WebPAC::Normalize::data_structure(
457                                            row => $row,
458                                            rules => $rules,
459                                            lookup => $lookup ? $lookup->lookup_hash : undef,
460                                            config => create_ds_config( $db_config, $database, $input, $mfn ),
461                                            marc_encoding => 'utf-8',
462                                    );
463    
464                                    $db->save_ds(
465                                            id => $mfn,
466                                            ds => $ds,
467                                            prefix => $input->{name},
468                                    ) if ($ds && !$stats);
469    
470                                    $indexer->add(
471                                            id => $input->{name} . "/" . $mfn,
472                                            ds => $ds,
473                                            type => $config->get($indexer_config)->{type},
474                                    ) if ($indexer && $ds);
475    
476                                    if ($marc) {
477                                            my $i = 0;
478    
479                                            while (my $fields = WebPAC::Normalize::_get_marc_fields( fetch_next => 1 ) ) {
480                                                    $marc->add(
481                                                            id => $mfn . ( $i ? "/$i" : '' ),
482                                                            fields => $fields,
483                                                            leader => WebPAC::Normalize::marc_leader(),
484                                                            row => $row,
485                                                    );
486                                                    $i++;
487                                            }
488    
489                                            $log->info("Created $i instances of MFN $mfn\n") if ($i > 1);
490                                    }
491    
492                                    $total_rows++;
493                          }                          }
494    
495                          my $ds = $n->data_structure($row);                          if ($validate) {
496                                    my $errors = $validate->report;
497                                    if ($errors) {
498                                            $log->info("validation errors:\n$errors\n" );
499                                            print $report_fh "$errors\n" if ($report_fh);
500                                    }
501                            }
502    
503                          $est->add(                          if ($stats) {
504                                  id => $input->{name} . "/" . $mfn,                                  my $s = $input_db->stats;
505                                  ds => $ds,                                  $log->info("statistics of fields usage:\n$s");
506                                  type => $config->{hyperestraier}->{type},                                  print $report_fh "Statistics of fields usage:\n$s" if ($report_fh);
507                          );                          }
508    
509                          $total_rows++;                          # close MARC file
510                            $marc->finish if ($marc);
511    
512                            # close report
513                            close($report_fh) if ($report_fh)
514                  }                  }
515    
516          };          }
517    
518            eval { $indexer->finish } if ($indexer && $indexer->can('finish'));
519    
520          my $dt = time() - $start_t;          my $dt = time() - $start_t;
521          $log->info("$total_rows records indexed in " .          $log->info("$total_rows records ", $indexer ? "indexed " : "",
522                  sprintf("%.2f sec [%.2f rec/sec]",                  sprintf("in %.2f sec [%.2f rec/sec]",
523                          $dt, ($total_rows / $dt)                          $dt, ($total_rows / $dt)
524                  )                  )
525          );          );
526    
527          #  
528          # add Hyper Estraier links to other databases          # end forked process
529          #          if ($parallel) {
530          if (ref($db_config->{links}) eq 'ARRAY') {                  $log->info("parallel process $$ finished");
531                  foreach my $link (@{ $db_config->{links} }) {                  exit(0);
                         $log->info("adding link $database -> $link->{to} [$link->{credit}]");  
                         $est->add_link(  
                                 from => $database,  
                                 to => $link->{to},  
                                 credit => $link->{credit},  
                         );  
                 }  
532          }          }
533    
534  }  }
535    
536    if ($parallel) {
537            # wait all children to finish
538            sleep(1) while wait != -1;
539            $log->info("all parallel processes finished");
540    }
541    
542    #
543    # handle links or merge after indexing
544    #
545    
546    if ($merge) {
547            print $estcmd_fh 'sudo /etc/init.d/hyperestraier start',$/;
548            close($estcmd_fh);
549            chmod 0700, $estcmd_path || $log->warn("can't chmod 0700 $estcmd_path: $!");
550            system $estcmd_path;
551    } else {
552            foreach my $link (@links) {
553                    $log->logdie("coderef in link ", Dumper($link), " is ", ref($link), " and not CODE") unless (ref($link) eq 'CODE');
554                    $link->();
555            }
556    }

Legend:
Removed from v.416  
changed lines
  Added in v.707

  ViewVC Help
Powered by ViewVC 1.1.26