Diff for /loncom/metadata_database/searchcat.pl between versions 1.33 and 1.50

version 1.33, 2003/06/19 19:34:27 version 1.50, 2003/12/26 15:13:48
Line 56  This script also does general database m Line 56  This script also does general database m
 the C<loncapa:metadata> table if it is deprecated.  the C<loncapa:metadata> table if it is deprecated.
   
 This script evaluates dynamic metadata from the authors'  This script evaluates dynamic metadata from the authors'
 F<nohist_resevaldata.db> database file in order to store it in MySQL, as  F<nohist_resevaldata.db> database file in order to store it in MySQL.
 well as to compress the filesize (add up all "count"-type metadata).  
   
 This script is playing an increasingly important role for a loncapa  This script is playing an increasingly important role for a loncapa
 library server.  The proper operation of this script is critical for a smooth  library server.  The proper operation of this script is critical for a smooth
Line 65  and correct user experience. Line 64  and correct user experience.
   
 =cut  =cut
   
   use strict;
   
 use lib '/home/httpd/lib/perl/';  use lib '/home/httpd/lib/perl/';
 use LONCAPA::Configuration;  use LONCAPA::Configuration;
   
Line 74  use DBI; Line 75  use DBI;
 use GDBM_File;  use GDBM_File;
 use POSIX qw(strftime mktime);  use POSIX qw(strftime mktime);
   
   require "find.pl";
   
 my @metalist;  my @metalist;
   
   my $simplestatus='';
   my %countext=();
   
   # ----------------------------------------------------- write out simple status
   sub writesimple {
       open(SMP,'>/home/httpd/html/lon-status/mysql.txt');
       print SMP $simplestatus."\n";
       close(SMP);
   }
   
   sub writecount {
       open(RSMP,'>/home/httpd/html/lon-status/rescount.txt');
       foreach (keys %countext) {
    print RSMP $_.'='.$countext{$_}.'&';
       }
       print RSMP 'time='.time."\n";
       close(RSMP);
   }
   
   # -------------------------------------- counts files with different extensions
   sub count {
       my $file=shift;
       $file=~/\.(\w+)$/;
       my $ext=lc($1);
       if (defined($countext{$ext})) {
    $countext{$ext}++;
       } else {
    $countext{$ext}=1;
       }
   }
 # ----------------------------------------------------- Un-Escape Special Chars  # ----------------------------------------------------- Un-Escape Special Chars
   
 sub unescape {  sub unescape {
Line 93  sub escape { Line 125  sub escape {
     return $str;      return $str;
 }  }
   
   
 # ------------------------------------------- Code to evaluate dynamic metadata  # ------------------------------------------- Code to evaluate dynamic metadata
   
 sub dynamicmeta {  sub dynamicmeta {
   
     my $url=&declutter(shift);      my $url=&declutter(shift);
     $url=~s/\.meta$//;      $url=~s/\.meta$//;
     my %returnhash=();      my %returnhash=(
       'count' => 0,
       'course' => 0,
       'course_list' => '',
       'avetries' => 'NULL',
       'avetries_list' => '',
       'stdno' => 0,
       'stdno_list' => '',
       'usage' => 0,
       'usage_list' => '',
       'goto' => 0,
       'goto_list' => '',
       'comefrom' => 0,
       'comefrom_list' => '',
       'difficulty' => 'NULL',
       'difficulty_list' => '',
                       'clear' => 'NULL',
                       'technical' => 'NULL',
       'correct' => 'NULL',
       'helpful' => 'NULL',
       'depth' => 'NULL',
       'comments' => ''
       );
     my ($adomain,$aauthor)=($url=~/^(\w+)\/(\w+)\//);      my ($adomain,$aauthor)=($url=~/^(\w+)\/(\w+)\//);
     my $prodir=&propath($adomain,$aauthor);      my $prodir=&propath($adomain,$aauthor);
     if ((tie(%evaldata,'GDBM_File',  
              $prodir.'/nohist_resevaldata.db',&GDBM_READER(),0640)) &&  # Get metadata except counts
         (tie(%newevaldata,'GDBM_File',      if (tie(my %evaldata,'GDBM_File',
              $prodir.'/nohist_new_resevaldata.db',&GDBM_WRCREAT(),0640))) {              $prodir.'/nohist_resevaldata.db',&GDBM_READER(),0640)) {
         my %sum=();   my %sum=();
         my %cnt=();   my %cnt=();
         my %listitems=('count'        => 'add',   my %concat=();
                        'course'       => 'add',   my %listitems=(
                        'avetries'     => 'avg',         'course'       => 'add',
                        'stdno'        => 'add',         'goto'         => 'add',
                        'difficulty'   => 'avg',         'comefrom'     => 'add',
                        'clear'        => 'avg',         'avetries'     => 'avg',
                        'technical'    => 'avg',         'stdno'        => 'add',
                        'helpful'      => 'avg',         'difficulty'   => 'avg',
                        'correct'      => 'avg',         'clear'        => 'avg',
                        'depth'        => 'avg',         'technical'    => 'avg',
                        'comments'     => 'app',         'helpful'      => 'avg',
                        'usage'        => 'cnt'         'correct'      => 'avg',
                        );         'depth'        => 'avg',
         my $regexp=$url;         'comments'     => 'app',
         $regexp=~s/(\W)/\\$1/g;         'usage'        => 'cnt'
         $regexp='___'.$regexp.'___([a-z]+)$';         );
         foreach (keys %evaldata) {  
             my $key=&unescape($_);   my $regexp=$url;
             if ($key=~/$regexp/) {   $regexp=~s/(\W)/\\$1/g;
                 my $ctype=$1;   $regexp='___'.$regexp.'___([a-z]+)$';
                 if (defined($cnt{$ctype})) {    while (my ($esckey,$value)=each %evaldata) {
                     $cnt{$ctype}++;       my $key=&unescape($esckey);
                 } else {       if ($key=~/$regexp/) {
                     $cnt{$ctype}=1;    my ($item,$purl,$cat)=split(/___/,$key);
                 }   if (defined($cnt{$cat})) { $cnt{$cat}++; } else { $cnt{$cat}=1; }
                 unless ($listitems{$ctype} eq 'app') {   unless ($listitems{$cat} eq 'app') {
                     if (defined($sum{$ctype})) {      if (defined($sum{$cat})) {
                         $sum{$ctype}+=$evaldata{$_};   $sum{$cat}+=&unescape($evaldata{$esckey});
                     } else {   $concat{$cat}.=','.$item;
                         $sum{$ctype}=$evaldata{$_};      } else {
                     }   $sum{$cat}=&unescape($evaldata{$esckey});
                 } else {   $concat{$cat}=$item;
                     if (defined($sum{$ctype})) {      }
                         if ($evaldata{$_}) {   } else {
                             $sum{$ctype}.='<hr>'.$evaldata{$_};      if (defined($sum{$cat})) {
                         }   if ($evaldata{$esckey}=~/\w/) {
                     } else {      $sum{$cat}.='<hr />'.&unescape($evaldata{$esckey});
                         $sum{$ctype}=''.$evaldata{$_};   }
                     }      } else {
                 }   $sum{$cat}=''.&unescape($evaldata{$esckey});
                 if ($ctype ne 'count') {      }
                     $newevaldata{$_}=$evaldata{$_};   }
                 }      }
             }   }
         }   untie(%evaldata);
         foreach (keys %cnt) {  # transfer gathered data to returnhash, calculate averages where applicable
             if ($listitems{$_} eq 'avg') {   while (my $cat=each(%cnt)) {
                 $returnhash{$_}=int(($sum{$_}/$cnt{$_})*100.0+0.5)/100.0;      if ($cnt{$cat} eq 'nan') { next; }
             } elsif ($listitems{$_} eq 'cnt') {      if ($sum{$cat} eq 'nan') { next; }
                 $returnhash{$_}=$cnt{$_};      if ($listitems{$cat} eq 'avg') {
             } else {   if ($cnt{$cat}) {
                 $returnhash{$_}=$sum{$_};      $returnhash{$cat}=int(($sum{$cat}/$cnt{$cat})*100.0+0.5)/100.0;
             }   } else {
         }      $returnhash{$cat}='NULL';
         if ($returnhash{'count'}) {   }
             my $newkey=$$.'_'.time.'_searchcat___'.&escape($url).'___count';      } elsif ($listitems{$cat} eq 'cnt') {
             $newevaldata{$newkey}=$returnhash{'count'};   $returnhash{$cat}=$cnt{$cat};
         }      } else {
         untie(%evaldata);   $returnhash{$cat}=$sum{$cat};
         untie(%newevaldata);      }
       $returnhash{$cat.'_list'}=$concat{$cat};
    }
       }
   # get count
       if (tie(my %evaldata,'GDBM_File',
               $prodir.'/nohist_accesscount.db',&GDBM_READER(),0640)) {
    my $escurl=&escape($url);
    if (! exists($evaldata{$escurl})) {
       $returnhash{'count'}=0;
    } else {
       $returnhash{'count'}=$evaldata{$escurl};
    }
    untie %evaldata;
     }      }
     return %returnhash;      return %returnhash;
 }  }
     
 # ----------------- Code to enable 'find' subroutine listing of the .meta files  
 require "find.pl";  
 sub wanted {  
     (($dev,$ino,$mode,$nlink,$uid,$gid) = lstat($_)) &&  
         -f _ &&  
         /^.*\.meta$/ && !/^.+\.\d+\.[^\.]+\.meta$/ &&  
         push(@metalist,"$dir/$_");  
 }  
   
 # ---------------  Read loncapa_apache.conf and loncapa.conf and get variables  # ---------------  Read loncapa_apache.conf and loncapa.conf and get variables
 my $perlvarref=LONCAPA::Configuration::read_conf('loncapa.conf');  my $perlvarref=LONCAPA::Configuration::read_conf('loncapa.conf');
 my %perlvar=%{$perlvarref};  my %perlvar=%{$perlvarref};
 undef $perlvarref; # remove since sensitive and not needed  undef $perlvarref;
 delete $perlvar{'lonReceipt'}; # remove since sensitive and not needed  delete $perlvar{'lonReceipt'}; # remove since sensitive and not needed
   
 # ------------------------------------- Only run if machine is a library server  # ------------------------------------- Only run if machine is a library server
Line 195  exit unless $perlvar{'lonRole'} eq 'libr Line 251  exit unless $perlvar{'lonRole'} eq 'libr
   
 my $wwwid=getpwnam('www');  my $wwwid=getpwnam('www');
 if ($wwwid!=$<) {  if ($wwwid!=$<) {
     $emailto="$perlvar{'lonAdmEMail'},$perlvar{'lonSysEMail'}";      my $emailto="$perlvar{'lonAdmEMail'},$perlvar{'lonSysEMail'}";
     $subj="LON: $perlvar{'lonHostID'} User ID mismatch";      my $subj="LON: $perlvar{'lonHostID'} User ID mismatch";
     system("echo 'User ID mismatch. searchcat.pl must be run as user www.' |\      system("echo 'User ID mismatch. searchcat.pl must be run as user www.' |\
  mailto $emailto -s '$subj' > /dev/null");   mailto $emailto -s '$subj' > /dev/null");
     exit 1;      exit 1;
Line 207  if ($wwwid!=$<) { Line 263  if ($wwwid!=$<) {
   
 open(LOG,'>'.$perlvar{'lonDaemons'}.'/logs/searchcat.log');  open(LOG,'>'.$perlvar{'lonDaemons'}.'/logs/searchcat.log');
 print LOG '==== Searchcat Run '.localtime()."====\n\n";  print LOG '==== Searchcat Run '.localtime()."====\n\n";
   $simplestatus='time='.time.'&';
 my $dbh;  my $dbh;
 # ------------------------------------- Make sure that database can be accessed  # ------------------------------------- Make sure that database can be accessed
 {  {
Line 214  my $dbh; Line 271  my $dbh;
     $dbh = DBI->connect("DBI:mysql:loncapa","www",$perlvar{'lonSqlAccess'},{ RaiseError =>0,PrintError=>0})      $dbh = DBI->connect("DBI:mysql:loncapa","www",$perlvar{'lonSqlAccess'},{ RaiseError =>0,PrintError=>0})
     ) {       ) { 
  print LOG "Cannot connect to database!\n";   print LOG "Cannot connect to database!\n";
    $simplestatus.='mysql=defunct';
    &writesimple();
  exit;   exit;
     }      }
     my $make_metadata_table = "CREATE TABLE IF NOT EXISTS metadata (".  
   # Make temporary table
       $dbh->do("DROP TABLE IF EXISTS newmetadata");
       my $make_metadata_table = "CREATE TABLE IF NOT EXISTS newmetadata (".
         "title TEXT, author TEXT, subject TEXT, url TEXT, keywords TEXT, ".          "title TEXT, author TEXT, subject TEXT, url TEXT, keywords TEXT, ".
         "version TEXT, notes TEXT, abstract TEXT, mime TEXT, language TEXT, ".          "version TEXT, notes TEXT, abstract TEXT, mime TEXT, language TEXT, ".
         "creationdate DATETIME, lastrevisiondate DATETIME, owner TEXT, ".          "creationdate DATETIME, lastrevisiondate DATETIME, owner TEXT, ".
         "copyright TEXT, FULLTEXT idx_title (title), ".          "copyright TEXT, dependencies TEXT, ".
           "count INTEGER UNSIGNED, ".
           "course INTEGER UNSIGNED, course_list TEXT, ".
           "goto INTEGER UNSIGNED, goto_list TEXT, ".
           "comefrom INTEGER UNSIGNED, comefrom_list TEXT, ".
           "sequsage INTEGER UNSIGNED, sequsage_list TEXT, ".
           "stdno INTEGER UNSIGNED, stdno_list TEXT, ".
    "avetries FLOAT, avetries_list TEXT, ".
           "difficulty FLOAT, difficulty_list TEXT, ".
    "clear FLOAT, technical FLOAT, correct FLOAT, helpful FLOAT, depth FLOAT, ".
    "comments TEXT, ".
           "FULLTEXT idx_title (title), ".
         "FULLTEXT idx_author (author), FULLTEXT idx_subject (subject), ".          "FULLTEXT idx_author (author), FULLTEXT idx_subject (subject), ".
         "FULLTEXT idx_url (url), FULLTEXT idx_keywords (keywords), ".          "FULLTEXT idx_url (url), FULLTEXT idx_keywords (keywords), ".
         "FULLTEXT idx_version (version), FULLTEXT idx_notes (notes), ".          "FULLTEXT idx_version (version), FULLTEXT idx_notes (notes), ".
         "FULLTEXT idx_abstract (abstract), FULLTEXT idx_mime (mime), ".          "FULLTEXT idx_abstract (abstract), FULLTEXT idx_mime (mime), ".
         "FULLTEXT idx_language (language), FULLTEXT idx_owner (owner), ".          "FULLTEXT idx_language (language), FULLTEXT idx_owner (owner), ".
         "FULLTEXT idx_copyright (copyright)) TYPE=MYISAM";          "FULLTEXT idx_copyright (copyright)) ".
           "TYPE=MyISAM";
     # It would sure be nice to have some logging mechanism.      # It would sure be nice to have some logging mechanism.
     $dbh->do($make_metadata_table);      unless ($dbh->do($make_metadata_table)) {
    print LOG "\nMySQL Error Create: ".$dbh->errstr."\n";
    die $dbh->errstr;
       }
 }  }
   
 # ------------------------------------------------------------- get .meta files  # ------------------------------------------------------------- get .meta files
Line 237  my @homeusers = grep { Line 314  my @homeusers = grep {
     &ishome("$perlvar{'lonDocRoot'}/res/$perlvar{'lonDefDomain'}/$_")      &ishome("$perlvar{'lonDocRoot'}/res/$perlvar{'lonDefDomain'}/$_")
     } grep {!/^\.\.?$/} readdir(RESOURCES);      } grep {!/^\.\.?$/} readdir(RESOURCES);
 closedir RESOURCES;  closedir RESOURCES;
   
   #
   # Create the statement handlers we need
   
   my $insert_sth = $dbh->prepare
       ("INSERT INTO newmetadata VALUES (".
        "?,".   # title
        "?,".   # author
        "?,".   # subject
        "?,".   # declutter url
        "?,".   # version
        "?,".   # current
        "?,".   # notes
        "?,".   # abstract
        "?,".   # mime
        "?,".   # language
        "?,".   # creationdate
        "?,".   # revisiondate
        "?,".   # owner
        "?,".   # copyright
        "?,".   # dependencies
        "?,".   # count
        "?,".   # course
        "?,".   # course_list
        "?,".   # goto
        "?,".   # goto_list
        "?,".   # comefrom
        "?,".   # comefrom_list
        "?,".   # usage
        "?,".   # usage_list
        "?,".   # stdno
        "?,".   # stdno_list
        "?,".   # avetries
        "?,".   # avetries_list
        "?,".   # difficulty
        "?,".   # difficulty_list
        "?,".   # clear
        "?,".   # technical
        "?,".   # correct
        "?,".   # helpful
        "?,".   # depth
        "?".    # comments
        ")"
        );
   
 foreach my $user (@homeusers) {  foreach my $user (@homeusers) {
     print LOG "\n=== User: ".$user."\n\n";      print LOG "\n=== User: ".$user."\n\n";
     # Remove left-over db-files from potentially crashed searchcat run  
     my $prodir=&propath($perlvar{'lonDefDomain'},$user);      my $prodir=&propath($perlvar{'lonDefDomain'},$user);
     unlink($prodir.'/nohist_new_resevaldata.db');  
     # Use find.pl      # Use find.pl
     undef @metalist;      undef @metalist;
     @metalist=();      @metalist=();
Line 254  foreach my $user (@homeusers) { Line 375  foreach my $user (@homeusers) {
         my $ref=&metadata($m);          my $ref=&metadata($m);
         my $m2='/res/'.&declutter($m);          my $m2='/res/'.&declutter($m);
         $m2=~s/\.meta$//;          $m2=~s/\.meta$//;
         &dynamicmeta($m2);    if ($ref->{'obsolete'}) { print LOG "obsolete\n"; next; }
         my $q2="select * from metadata where url like binary '$m2'";   if ($ref->{'copyright'} eq 'private') { print LOG "private\n"; next; }
         my $sth = $dbh->prepare($q2);          my %dyn=&dynamicmeta($m2);
         $sth->execute();   &count($m2);
         my $r1=$sth->fetchall_arrayref;          unless ($insert_sth->execute(
         if (@$r1) {       $ref->{'title'},
             $sth=$dbh->prepare("delete from metadata where url like binary '$m2'");                               $ref->{'author'},
             $sth->execute();                               $ref->{'subject'},
         }                               $m2,
         $sth=$dbh->prepare('insert into metadata values ('.                               $ref->{'keywords'},
                            '"'.delete($ref->{'title'}).'"'.','.                               'current',
                            '"'.delete($ref->{'author'}).'"'.','.                               $ref->{'notes'},
                            '"'.delete($ref->{'subject'}).'"'.','.                               $ref->{'abstract'},
                            '"'.$m2.'"'.','.                               $ref->{'mime'},
                            '"'.delete($ref->{'keywords'}).'"'.','.                               $ref->{'language'},
                            '"'.'current'.'"'.','.                               sqltime($ref->{'creationdate'}),
                            '"'.delete($ref->{'notes'}).'"'.','.                               sqltime($ref->{'lastrevisiondate'}),
                            '"'.delete($ref->{'abstract'}).'"'.','.                               $ref->{'owner'},
                            '"'.delete($ref->{'mime'}).'"'.','.                               $ref->{'copyright'},
                            '"'.delete($ref->{'language'}).'"'.','.       $ref->{'dependencies'},
                            '"'.sqltime(delete($ref->{'creationdate'})).'"'.','.       $dyn{'count'},
                            '"'.sqltime(delete($ref->{'lastrevisiondate'})).'"'.','.       $dyn{'course'},
                            '"'.delete($ref->{'owner'}).'"'.','.       $dyn{'course_list'},
                            '"'.delete($ref->{'copyright'}).'"'.')');       $dyn{'goto'},
         $sth->execute();       $dyn{'goto_list'},
        $dyn{'comefrom'},
        $dyn{'comefrom_list'},
        $dyn{'usage'},
        $dyn{'usage_list'},
        $dyn{'stdno'},
        $dyn{'stdno_list'},
        $dyn{'avetries'},
        $dyn{'avetries_list'},
        $dyn{'difficulty'},
        $dyn{'difficulty_list'},     
        $dyn{'clear'},
        $dyn{'technical'},
        $dyn{'correct'},
        $dyn{'helpful'},
        $dyn{'depth'},
        $dyn{'comments'}     
        )) {
       print LOG "\nMySQL Error Insert: ".$dbh->errstr."\n";
       die $dbh->errstr;
    }
           $ref = undef;
     }      }
       
     # --------------------------------------------------- Clean up database  
     # Need to, perhaps, remove stale SQL database records.  
     # ... not yet implemented  
           
     # ------------------------------------------- Copy over the new db-files  
     system('mv '.$prodir.'/nohist_new_resevaldata.db '.  
            $prodir.'/nohist_resevaldata.db');  
 }  }
 # --------------------------------------------------- Close database connection  # --------------------------------------------------- Close database connection
 $dbh->disconnect;  $dbh->do("DROP TABLE IF EXISTS metadata");
   unless ($dbh->do("RENAME TABLE newmetadata TO metadata")) {
       print LOG "\nMySQL Error Rename: ".$dbh->errstr."\n";
       die $dbh->errstr;
   }
   unless ($dbh->disconnect) {
       print LOG "\nMySQL Error Disconnect: ".$dbh->errstr."\n";
       die $dbh->errstr;
   }
 print LOG "\n==== Searchcat completed ".localtime()." ====\n";  print LOG "\n==== Searchcat completed ".localtime()." ====\n";
 close(LOG);  close(LOG);
   &writesimple();
   &writecount();
 exit 0;  exit 0;
   
   
Line 303  exit 0; Line 447  exit 0;
 # significantly altered from subroutine present in lonnet  # significantly altered from subroutine present in lonnet
 sub metadata {  sub metadata {
     my ($uri,$what)=@_;      my ($uri,$what)=@_;
     my %metacache;      my %metacache=();
     $uri=&declutter($uri);      $uri=&declutter($uri);
     my $filename=$uri;      my $filename=$uri;
     $uri=~s/\.meta$//;      $uri=~s/\.meta$//;
Line 417  sub unsqltime { Line 561  sub unsqltime {
     return $timestamp;      return $timestamp;
 }  }
   
   # ----------------- Code to enable 'find' subroutine listing of the .meta files
   
   no strict "vars";
   
   sub wanted {
       (($dev,$ino,$mode,$nlink,$uid,$gid) = lstat($_)) &&
            -f _ &&
            /^.*\.meta$/ && !/^.+\.\d+\.[^\.]+\.meta$/ &&
            push(@metalist,"$dir/$_");
   }

Removed from v.1.33  
changed lines
  Added in v.1.50


FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>