Wie arbeiten AltaVista, Hotbot, Yahoo und Konsorten? Sie hetzen Herden von Robots, Spiders und ähnlichem Getier 24 Stunden am Tag quer durchs Internet und schnappen HTML-Seiten. Daß ein Search-Engine jedoch auf die Frage Welche Dokumente enthalten die Daten, die ich suche? kluge Antworten geben kann, erfordert mehr: Ausgefeilte Software muß die Dokumente analysieren und eine Schlagwort-Datenbank aufbauen. Auf eine Suchanfrage (Query) hin spuckt ein derartiges System die Namen der Dokumente aus, die die verlangten Schlagworte möglichst oft enthalten und - so jedenfalls die Theorie - inhaltlich am ehesten dem Gesuchten entsprechen.
Auch wenn man nicht gerade den Ehrgeiz hat, das gesamte Internet zu durchstöbern, sondern nur eine größere Website mit einer intelligenten Suchfunktion ausstatten will, steht man früher oder später vor dem Problem der Indizierung. Zum Glück gibt's hierfür bereits funktionierende Software! Und sogar kostenlos!
freeWAIS-sf
basiert auf einem Produkt
der (mittlerweile nicht mehr
existierenden) Firma WAIS zur Indizierung von frei
formatierten Texten bzw. der Stichwortsuche in denselben.
freeWAIS-sf
läuft unter Linux und anderen gängigen Unix-Plattformen und
ist ruck-zuck installiert (siehe Kasten:
freeWAIS-sf
: Installation und Indizierung).
Lauscht der neue WAIS-Server einmal auf dem eingestellten Port,
dürfen Clients wie das nachfolgend vorgestellte CGI-Skript search.pl
Suchanfragen stellen und bekommen passende Dokumente als Antwort.
Abbildung 1 zeigt search.pl
in Aktion. Es liegt im cgi-bin
des Webservers und gibt
gerade darüber Auskunft, welche Dokumente auf meiner lokalen Test-Website
die Begriffe muen*
(könnte auf die bayrische Landeshauptstadt passen)
und san francisco
enthalten, und, siehe da, das einzig passende ist - mein
Lebenslauf, der, relativ zum Webserver im Unterverzeichnis webpage
hängt.
Selbstverständlich fördert ein Mausklick auf den angezeigten Namen das
entsprechende Dokument zutage.
Abb.1: Stichwortsuche mit dem CGI-Skript |
Der WAIS-Engine versteht - und das ist der Vorteil gegenüber
einfachen Suchprogrammen wie grep
- auch komplexere Suchbegriffe wie
a AND b # Dokumente, die 'a' und 'b' enthalten a OR b # Dokumente, die 'a' oder 'b' enthalten a NOT b # Dokumente, die 'a', aber nicht 'b' enthalten a b # Dokumente, die 'a' oder 'b' enthalten "a b" # Dokumente, die die Zeichenkette "a b" enthalten a* # Dokumente, die Wörter enthalten, die mit 'a' beginnen
und liefert wirklich nur die Dokumente, deren Inhalt allen Bedingungen genügt.
Die Perl-Schnittstelle Wais.pm
von Ulrich Pfeifer, vom
CPAN geholt und installiert (siehe Kasten
Wais.pm
installieren), bietet derart komfortablen
High-Level Zugriff auf den WAIS-Server, daß search.pl
mit nur 77
Zeilen Code auskommt. Es
nimmt einen Query-String vom Benutzer entgegen, sendet ihn an den WAIS-Server,
erhält von dort die Namen passender Dokumente und zeigt diese anschließend
als HTML-Hyperlinks an.
Wie aus Listing 1 hervorgeht, greift sich search.pl
in Zeile 6 das
für CGI-Skripts unverzichtbare CGI.pm
(kommt mit perl5.004
)
und importiert auch
gleich - entgegen meiner
sonstigen Maxime - die wichtigsten Funktionen. Dies hat zur Folge, dass
auch ohne ein explizit erzeugtes CGI-Objekt Funktionen wie header()
(gibt den HTTP-Header aus) oder h1()
(schreibt eine HTML-Überschrift)
zur Verfügung stehen.
Zeile 7 holt das frisch installierte Wais.pm
-Modul herein. Die Zeilen
12 bis 15 definieren Parameterwerte, die an lokale Gegebenheiten anzupassen
sind. Da der WAIS-Server Zugriffspfade von Dokumenten entsprechend dem
File-System spezifiziert, muß das Skript zur Umwandlung von
lokalen File-System-Pfaden in globale URLs wissen, wo das Dokumentenverzeichnis
des HTTP-Servers relativ zur Unix-Wurzel liegt ($htdocs_path
).
$hostname
ist der Name des Rechners, auf dem der WAIS-Server läuft,
$port
der zugehörige Port, $dbname
der Name der Datenbank -
alles Parameter, die bei der Installation bzw. der Indizierung festgelegt
werden.
Zeile 18 ruft die Funktion print_form()
auf,
die ab Zeile 59 den HTTP-Header sendet und
das Eingabeformular in den Browser zaubert. Liegt, wie beim ersten
Aufruf von search.pl
, keine Query-Eingabe vor, beendet Zeile 20 das
Skript ab. Trägt der Benutzer dann den Suchstring in das angezeigte Textfeld ein
und drückt die Eingabetaste, startet search.pl
erneut - und diesmal
liefert param("query")
den Query entsprechend dem Inhalt des Textfeldes.
Die Funktion Wais::Search
in Zeile 23 nimmt Kontakt zum WAIS-Server auf,
der wiederum seine Datenbank durchsucht und das Ergebnis wieder über die
aufgebaute TCP-Verbindung zurückschickt. search.pl
sieht nichts
von alledem - nur $result
, ein Objekt der Klasse Wais::Result
.
Die Methode header()
gibt ein Array von Referenzen zurück, deren
jede wiederum auf ein Array mit den Elementen
$tag, $score, $lines, $bytes, $headline
verweist.
$tag
ist hierbei der Name der WAIS-Datenbank, die für das Ergebnis
verantwortlich zeichnet, $score
die Trefferquote, $lines
und
$bytes
die Länge des gefundenen Dokuments in Zeilen bzw. Bytes.
In $headline
liegen der Dateiname des Dokuments und, durch Leerzeichen
getrennt, der Zugriffspfad relativ zum Dateisystem.
Zeile 33 ermittelt die Länge des Ergebnis-Arrays - die Anzahl der Treffer. Doch, halt, eine Ausnahme gibt's: Für den Fall, daß nichts gefunden wurde oder ein Fehler aufgetreten ist, kommt ein Eintrag zurück, dessen Score-Feld auf Null gesetzt ist.
Ist, wie Zeile 28 prüft, die Anzahl der Ergebnisse gleich Null ($#results
liefert Eins weniger als die Länge von @results
), muß ein Fehler
aufgetreten sein, wahrscheinlich läuft der WAIS-Server nicht. search.pl
zeigt daraufhin eine Fehlermeldung in Rot an und bricht ab.
Sonst gibt Zeile 40 die (korrigierte) Anzahl der Treffer aus und ab
Zeile 42 beginnt eine for
-Schleife, die über alle Treffer iteriert,
die Pfad-Datei-Informationen vom WAIS-Server in URLs umwandelt und
als HTML-Links in einer Tabelle anzeigt. Die td()
, TR()
, a()
und
table()
-Funktionen des CGI.pm
-Moduls sehen zwar kryptisch aus,
verkürzen jedoch den Code beträchtlich, und verleihen einem, hat man sie mal
verstanden - grenzenlooose Maaaacht, huaaah ...
freeWAIS-sf
: Installation und IndizierungfreeWAIS-sf
von Ulrich Pfeifer zeichnet sich gegenüber dem originalen
WAIS-Engine durch die Einbindung sogenannter structured fields aus:
in Dokumenten eingebettete Felder, die dem Indizierer
ein wenig von der Dokument-Struktur vermitteln sollen, statt nur auf
den Inhalt loszugehen. Die im Artikel besprochene Anwendung macht von
diesem Feature keinen Gebrauch, schaden tut's jedoch nicht.
Die neueste Version von freeWAIS-sf
ist freeWAIS-sf-2.1.2.tar.gz
und liegt auf
ftp://ftp.wsct.wsc.com/pub/freeWAIS-sf/freeWAIS-sf-2.1/
oder einem der deutschen Spiegel, z.B.
ftp://ftp.leo.org/pub/comp/infosys/wais/freeWAIS/freeWAIS-sf-2.1/
zur Abholung bereit. Ausgepackt, konfiguriert, ge-maked und installiert wird folgendermaßen:
tar zxfv freeWAIS-sf-2.1.2.tar.gz cd freeWAIS-sf-2.1.2 ./configure make make install
./configure
wirft eine Reihe von Fragen auf, die jedoch durch stetes
Hämmern auf die Return-Taste schnell verschwinden. make install
erfordert
- im allgemeinen - Root-Rechte. Der fertige Build wird später noch benötigt.
Dafür, daß der noch zu startende WAIS-Server die Dokumente der
Website in seinem Index findet, sorgt das folgendes Shell-Script, welches
das mit der freeWAIS-sf
-Installation kommende Programm waisindex
aufruft
und ihm den Pfad zur Website, sowie das Verzeichnis, indem der Index
abgelegt wird, angibt:
WAISDIR=/usr/local/etc/httpd/wais WEBSITE=/usr/local/etc/httpd/htdocs WAISINDEX=/usr/local/bin/waisindex # Verzeichnis für WAIS-Datenbank anlegen if [ ! -d $WAISDIR ] then mkdir $WAISDIR fi cd $WAISDIR # Indizierung starten $WAISINDEX -r -d website $WEBSITE
Die WEBSITE
-Variable gibt den Pfad an, unter dem das Dokumentenverzeichnis
der zu indizierenen Website liegt.
Soll die Datenbank, wie in WAISDIR
angegeben, in einem Nebenverzeichnis des
Webservers liegen, benötigt das Skript natürlich die entsprechenden
Rechte, sonst tut's auch jedes andere Verzeichnis.
waisindex
ackert dabei rekursiv die gesamte Website durch, dieser
Vorgang kann, entsprechend der zu bearbeiteten Dokumentenzahl, etwas dauern.
Der eigentliche Server-Prozeß läßt sich über folgende Kommandozeile
starten:
/usr/local/bin/waisserver -d /usr/local/etc/httpd/wais -p 4711
Die angegebene Port-Nummer muß - klarerweise - mit der
im CGI-Script search.pl
angegebenen übereinstimmen, das über die -d
-Option
spezifizierte Verzeichnis entspricht dem waisindex
vorher mitgeteilten.
Damit der WAIS-Server zukünftig gleich beim Booten des Rechners startet,
empfiehlt es sich, folgende Zeilen in /etc/rc.d/rc.local
zu packen:
echo "Starting WAIS Server" /usr/local/bin/waisserver -d /usr/local/etc/httpd/wais \ -p 4711 -e /usr/var/log.wais &
Wais.pm
installierenDie Perl-Schnittstelle Wais.pm
zu installieren, ist etwas haarig, aber
machbar. Zunächst geht alles wie gewohnt: Ans CPAN, wahlweise
ftp://ftp.leo.org/pub/comp/programming/languages/perl/CPAN/ ftp://ftp.rz.ruhr-uni-bochum.de/pub/CPAN/ ftp://ftp.uni-hamburg.de/pub/soft/lang/perl/CPAN/
angedockt, findet sich unter modules/by-module/Wais
die Distribution
Wais-2.304.tar.gz
Diese entpackt sich wie gewohnt - und zwar am geschicktesten
im selben Verzeichnis wie vorher die freeWAIS-sf
-Distribution - mit
tar zxfv Wais-2.304.tar.gz
Doch vor dem 'make' sind einige wilde Aktionen mit
der freeWAIS-sf
-Distribution notwendig: So benötigt Wais.pm
die Include-Datei wais.h
sowie die Bibliothek libwais.a
. Beide
Dateien entstehen unter Mitwirkung des freeWAIS-sf
-Source-Codes.
Stehen, wie vorgeschlagen, freeWAIS-sf-2.1.2/
und Wais-2.304/
im gleichen Verzeichnis, geht das so:
cd freeWAIS-sf-2.1.2/ir perl ../../Wais-2.304/mkinc -I../ctype ui.h cutil.h irext.h \ irfiles.h irsearch.h irtfiles.h weight.h \ docid.h >/tmp/wais.h cd ../../Wais-2.304 mkdir tmp cd tmp ar x ../../freeWAIS-sf-2.1.2/ir/libwais.a ar x ../../freeWAIS-sf-2.1.2/regexp/libregexp.a ar x ../../freeWAIS-sf-2.1.2/lib/libftw.a cp ../../freeWAIS-sf-2.1.2/ctype/ctype.o . ar rc libwais.a *.o ranlib libwais.a cp libwais.a /tmp/libwais.a cd ..
Dann müssen wais.h
und libwais.a
, die noch unter
/tmp
liegen, dorthin, wo der Compiler sie
findet, also z.B. (als root
)
cp /tmp/wais.h /usr/local/include cp /tmp/libwais.a /usr/local/lib
Dann ist Wais-2.304
endlich startbereit:
cd Wais-2.304 perl Makefile.PL make
Der make
wirft eine Reihe von unkritischen Warnings auf,
läuft aber erfolgreich. Schließlich plaziert ein unter root
aufgerufenes
make install
das Modul Wais.pm
in den Perl-Modul-Pfad. Es gab schon einfachere
Installationen.
search.pl
01 #!/usr/bin/perl -wT 02 ########################################################################## 03 # search.pl - Stichwortsuche in einer WAIS Datenbank 04 # 05 # Michael Schilli, 1998 (mschilli@perlmeister.com) 06 ########################################################################## 07 08 use CGI qw/:form :html param header/; 09 use Wais; 10 11 ########################################################################## 12 # Konfiguration 13 ########################################################################## 14 $htdocs_path = "/usr/local/etc/httpd/htdocs"; 15 $dbname = "website"; 16 $hostname = "m1"; 17 $port = 4711; 18 ########################################################################## 19 20 print_form(); # Überschrift und Suchformular ausgeben 21 22 exit 0 unless param("query"); # Ohne spezifizierten Query ist hier Schluß 23 24 # Query ist angegeben, WAIS befragen 25 $result = Wais::Search({'query' => param("query"), 'database' => $dbname, 26 'host' => $hostname, 'port' => $port}); 27 28 @results = $result->header(); # Ergebnisse aufbereiten 29 30 if($#results < 0) { # Fehler aufgetreten? 31 print pre(font({color=>"red"}, "Error - WAIS server down?\n")); 32 return; 33 } 34 35 $nof_hits = $#results + 1; # Anzahl der Ergebnisse 36 37 if($nof_hits == 1) { # Ein Ergebnis mit Score 0 => Kein Treffer 38 my ($tag, $score) = @{$results[0]}; 39 $nof_hits = 0 unless $score; 40 } 41 42 print hr, i($nof_hits, " documents found\n"); # Anzahl Treffer 43 44 for(@results) { # Über Ergebnisse iterieren 45 46 my ($tag, $score, $lines, $bytes, $headline, $types, $docid) = @$_; 47 48 next unless $score; # Bogus-Ergebnis vergessen 49 50 # WAIS-Pfad in URL-Pfad umwandeln 51 my ($file, $path) = split(' ', $headline); 52 $path =~ s,^$htdocs_path/,,g; # File-System-prefix wegwerfen 53 # URL in Tabelle hängen 54 $rows .= TR(td( a({href=>"http://$hostname/$path$file"}, 55 "$path$file"))); 56 } 57 58 print table($rows); # Tabelle ausgeben 59 60 ########################################################################## 61 sub print_form { 62 ########################################################################## 63 64 print header, 65 start_html(-title => 'Website Search', 66 -BGCOLOR => 'white'), 67 center(h1("Search the Website")), 68 center(table(TR( 69 td( 70 p("Enter Query:")), 71 td( 72 start_form, 73 textfield(-name => 'query', 74 -value => (param('query') || ""), 75 -size => 40), 76 end_form, 77 )))), 78 end_html; 79 }
Michael Schilliarbeitet als Software-Engineer bei Yahoo! in Sunnyvale, Kalifornien. Er hat "Goto Perl 5" (deutsch) und "Perl Power" (englisch) für Addison-Wesley geschrieben und ist unter mschilli@perlmeister.com zu erreichen. Seine Homepage: http://perlmeister.com. |