Eine fehlertolerante Suchsoftware für Onlineshops DIPLOMARBEIT Zur Erlangung des akademischen Grades eines Magisters der Sozial- und Wirtschaftswissenschaften im Diplomstudium Wirtschaftsinformatik eingereicht an der Johannes Kepler Universität Linz Institut für Wirtschaftsinformatik Software Engineering Betreuung: a. Univ.-Prof. Mag. Dr. Reinhold Plösch
This document is posted to help you gain knowledge. Please leave a comment to let me know what you think about it! Share it to your friends and learn new things together.
Transcript
Eine fehlertolerante Suchsoftwarefür Onlineshops
DIPLOMARBEIT
Zur Erlangung des akademischen Gradeseines Magisters der Sozial- und Wirtschaftswissenschaften
im Diplomstudium Wirtschaftsinformatik
eingereicht an der Johannes Kepler Universität LinzInstitut für Wirtschaftsinformatik
Software Engineering
Betreuung:a. Univ.-Prof. Mag. Dr. Reinhold Plösch
Verfasst von: Andreas Wabro
St. Georgen/Gusen, im September 2005
ii
Ich erkläre hiermit, dass ich die vorliegende Diplomarbeit mit dem Titel „Eine fehlertolerante
Suchsoftware für Onlineshops“ eigenständig verfasst, andere als die angegebenen Quellen
und Hilfsmittel nicht benutzt und die aus anderen Quellen entnommenen Stellen als solche
gekennzeichnet habe.
St. Georgen/Gusen, 9. September 2005
iii
iv
Kurzfassung
Erlöse, die aus dem Verkauf von Produkten in Online-Shops erzielt werden, tragen
mittlerweile bei vielen Firmen wesentlich zum Gesamtumsatz bei. Um die Produktivität und
den Umsatz eines Online-Shops zu steigern ist unter anderem der Einsatz einer
leistungsfähigen Suchsoftware sinnvoll, da ein Großteil der Benutzer und potentiellen Käufer
die Suchfunktion der Webseite benutzen, um Produkte und Dienstleistungen zu finden. Findet
ein Benutzer aufgrund eines Tipp- oder Rechtschreibfehlers keine Produkte, so verlässt er
unter Umständen den Shop und kauft das gesuchte Produkt bei einem Konkurrenten. Zudem
kommt es oft vor, dass ein gesuchtes Produkt unter einem anderen Namen in der Datenbank
gespeichert ist und somit auch bei einem richtig geschriebenen Suchbegriff keine Produkte
gefunden werden.
Das Ziel dieser Diplomarbeit war es, eine fehlertolerante Suchsoftware zu entwickeln, welche
Tipp- und Rechtschreibfehler toleriert. Zudem wurde ein Thesaurus integriert um eine Suche
nach Synonymen und Unterbegriffen zu ermöglichen.
Der theoretische Teil dieser Arbeit zeigt Vor- und Nachteile verschiedener Suchalgorithmen
und Indizes, sowie deren Einsatzmöglichkeiten für eine fehlertolerante Suchsoftware im
Kontext von Online-Shops.
v
Abstract
Many companies generate a significant amount of their total revenue by sales in online shops.
In order to increase the productivity and the revenue of such shops, a powerful search engine
should be integrated, as a lot of users and potential customer use the search function in order
to find potential products and services. With common search functions, a user probably won’t
find a product, in case of misspelled search terms. As a result he may leave the shop and buy
the product at a competitor. Another common reason why search queries fail is that products
are stored under a different name in the companies’ database.
The aim of this diploma thesis was to implement a fault tolerant search engine, which handles
search term that contains spelling mistakes. Additionally a thesaurus was implemented so that
the engine automatically searches for terms that are related with the search term.
The theoretical part of this work demonstrates the advantages and disadvantages of several
search algorithms and indices as well as their usage in a fault tolerant search engine within the
Ein Großteil der bestehenden Onlineshops stellt dem Benutzer eine Suchfunktion zur
Verfügung. Ohne Suchfunktion muss ein Benutzer durch verschiedene Produktkategorien
navigieren und Auflistungen durchsuchen bis er letztlich das gesuchte Produkt findet oder
seine Suche ergebnislos abbricht. Da dieser Vorgang für den Benutzer relativ mühsam ist und
er oft nicht weiß in welcher Kategorie sich das gesuchte Produkt befindet, ist die Nutzung der
Suchfunktion sehr beliebt. Die Ergebnisse einer Suchanfrage sind jedoch häufig
unbefriedigend, da viele Suchfunktionen nur buchstabengetreu vergleichen. Tipp- und
Rechtschreibfehler werden nicht toleriert und führen daher zu keinen befriedigenden
Ergebnissen. Zudem, können Produkte, die unter einem anderem als den gesuchten Namen
gespeichert sind, nicht gefunden werden. Führt eine Suche zu einer leeren Ergebnisliste, so
erweckt dies beim Benutzer den Eindruck, dass sich das Produkt nicht im Sortiment des
Unternehmens befindet. Dies führt unter Umständen dazu, dass er den Online-Shop verlässt
und das Produkt bei einem Konkurrenten kauft.
Der Einsatz einer leistungsfähigen Suchsoftware ist daher dringend notwendig, da diese nicht
nur die Produktivität und Benutzbarkeit sondern auch den Umsatz eines Online-Shops
steigert.
1
Das Ziel dieser Diplomarbeit war die Realisierung einer fehlertoleranten Suchsoftware,
welche Tipp- und Rechtschreibfehler toleriert und definierte Synonyme und Unterbegriffe
eines Suchbegriffes findet.
1.2 Fehlertolerante Suchsoftware
Eine Suchsoftware setzt sich üblicherweise aus zwei Hauptkomponenten zusammen. Zum
einen sind dies, die von der Software verwendeten Suchalgorithmen und zum anderen der zu
durchsuchende Index. Ein Index wird zwar nicht unbedingt benötigt, da eine Suche auch
direkt auf Datenbanken oder sonstigen Datenträgern ausgeführt werden kann, für den Einsatz
in Online-Shops ist es jedoch sinnvoll einen solchen Index zu verwenden um Suchabfragen zu
beschleunigen und somit die Wartezeit für Benutzer zu verkürzen. Weiters sollte eine
Suchsoftware für Online-Shops über einen Thesaurus sowie über eine Komponente, zur
Protokollierung von Suchabfragen verfügen. Mittels eines Thesaurus kann die Software
gleichzeitig nach Synonymen und Unterbegriffen eines Suchbegriffes suchen. Dadurch muss
der Benutzer nicht genau wissen unter welchem Begriff ein bestimmtes Produkt gespeichert
ist. Eine Suche nach Fernseher kann somit auch zu Suchergebnissen mit der Bezeichnung
Fernsehgerät oder TV führen, falls diese Synonyme im Thesaurus gespeichert sind. Die
Protokollierung von Suchabfragen in Online-Shops ist wichtig, damit der Betreiber des
Systems weiß welche Produkte gefragt sind und ob diese auch gefunden werden. Falls sie im
Sortiment des Unternehmens vorhanden sind und nicht gefunden werden, so muss der
Thesaurus um entsprechende Einträge erweitert werden. Sind sie jedoch nicht vorhanden so
kann sich der Unternehmer entscheiden stark nachgefragte Produkte ins Sortiment
aufzunehmen.
Fehlertolerante Suchalgorithmen können in die Kategorien phonetische Algorithmen und
Algorithmen, welche die Ähnlichkeit zweier Zeichenketten berechnen, eingeteilt werden.
Phonetische Algorithmen versuchen in einem Text jene Wörter zu finden, die gleich oder
ähnlich wie der gesuchte Begriff ausgesprochen werden. Sie produzieren oft unbrauchbare
Ergebnisse, da sie auch Treffer beinhalten, die nicht wie der gesuchte Begriff ausgesprochen
werden. Aufgrund ihrer Unzuverlässigkeit sollten phonetische Algorithmen nicht oder nur in
Kombination mit einem Algorithmus der zweiten Kategorie verwendet werden. Für die
Berechnung der Ähnlichkeit zweier Zeichenketten, gibt es eine große Anzahl an Algorithmen.
2
Zu den schnellsten Vertretern gehören Bitparallele- und Filterungsalgorithmen. Bitparallele
Algorithmen nutzen den Umstand aus, dass CPUs heutiger Computer Rechenoperationen
parallel mit 32 oder 64 Bit durchführen. Filterungsalgorithmen versuchen hingegen möglichst
große Teile eines Textes zu verwerfen und nur potentielle Übereinstimmungen mittels eines
approximativen Algorithmus zu prüfen. Die beiden erwähnten Algorithmen berechnen die
Ähnlichkeit durch die Anzahl der Operationen die nötig sind um eine Zeichenkette durch
Einfügen, Löschen, Ersetzen und Austauschen von Buchstabe in eine andere Zeichenkette zu
transformieren. Dies hat jedoch den Nachteil, dass sie Wortvariationen nicht erkennen
können. Ein Beispiel hierfür ist eine Suche nach Druckerkabel im Text Kabel für Drucker.
Für dieses Problem gibt es so genannte Q-Gramm oder N-Gramm Algorithmen. Sie versuchen
auch Wortvariationen zu erkennen indem sie den Suchbegriff sowie den zu durchsuchenden
Text in Teilzeichenketten der Länge q teilen. Anschließend vergleichen sie die Anzahl
gemeinsamer Teilzeichenketten. Weist der Text in einem bestimmten Bereich sehr viele
gleicher Teilzeichenketten auf so wird angenommen, dass es dort eine Übereinstimmung mit
dem Suchbegriff gibt. Der Nachteil dieser Art von Algorithmen ist, dass sie im Gegensatz zu
den beiden vorhin beschriebenen sehr langsam sind und durch das Erstellen der
Teilzeichenketten mehr Speicherplatz benötigen.
Ein Index ist wie bereits erwähnt eine Datenstruktur, welche darauf ausgerichtet ist, die
Verarbeitungsgeschwindigkeit von Suchabfragen zu erhöhen. Ein Index soll jedoch nur
verwendet werden, wenn die Anzahl der Suchabfragen, größer als die Anzahl der Änderungen
des Index ist, da nicht nur die Erstellung sondern auch die Aktualisierung eines Index ein
Vielfaches der Zeit einer Suchabfrage kostet [BaNa04].
Bei der Auswahl eines Index ist unter anderem das Kriterium Speicherplatzverbrauch von
Bedeutung, da ein speicherschonender Index, im Hauptspeicher gehalten werden kann und so
langsame Zugriffe auf externe Datenträger vermieden werden. So benötigt zum Beispiel der
Suffix-Array den 3-fachen Speicherplatz des ursprünglichen Textes, was im Gegensatz zu
Datenstrukturen die in Form eines Baumes aufgebaut sind, relativ wenig ist. Einen noch
geringeren Speicherplatzbedarf weist der Invertierte Index auf. Dieser wächst ab einer
bestimmten Größe nur noch sublinar zur Textgröße an. Approximatives Suchen in Suffix-
Arrays ist schneller als in einem Invertierten Index. Kann der Suffix-Array jedoch auf Grund
seines Speicherplatzverbrauches nicht im Hauptspeicher gehalten werden so ist er um ein
vielfaches langsamer als ein invertierter Index der im Hauptspeicher Platz findet. Ein weiterer
Nachteil des Suffix-Array ist sein komplizierter Aufbau. Dem hingegen lässt sich ein
3
Invertierter Index sehr einfach erstellen und aktualisieren. Auch ist es möglich einen
Invertierten Index auf mehrere Computer aufzuteilen, womit sich die Geschwindigkeit von
Suchabfragen weiter steigern lässt und sich das Problem des begrenzten Hauptspeicherplatzes
verringert.
Eine fehlertolerante Suchsoftware verfügt daher idealerweise über einen oder mehrere
schnelle Suchalgorithmen, einem speicherschonenden Index sowie über einen Thesaurus und
einer Protokollierungskomponente.
1.3 Prototyp
Für die Realisierung des Prototyps wurden zuerst verschiedene Suchalgorithmen und Indizes
verglichen und diese auf einen möglichen Einsatz in der Suchsoftware geprüft. Anschließend
wurden zwei Anwendungsszenarien beschrieben und daraus funktionale und nicht funktionale
Anforderungen abgeleitet.
Da die Implementierung der Software auf dem Suchframework Lucene aufbaut, war es
erforderlich sich zuerst einen Überblick über das Framework zu verschaffen und es auf nötige
Änderungen und Erweiterungen zu prüfen. Für die Auswahl des Frameworks Lucene waren
die Eigenschaften, dass es auf Java basiert, einen invertierten Index verwendet und bereits
grundlegende Suchfunktionen bereitstellt, von entscheidender Bedeutung. Neben Lucene
kamen auch das Testframework JUnit, das Build-Werkzeug ANT, die Bibliothek Log4J und
Phonetix, der XML Parser Xerxces 2, sowie das Webapplikationsframework Struts und das
Lasttestwerkzeug JMeter zum Einsatz.
Der erstellte Prototyp stellt Funktionen für eine exakte, fehlertolerante und phonetische Suche
zur Verfügung. Zudem können Suchergebnisse sortiert und durch Angabe von
Wertebereichen eingeschränkt werden. Die Software speichert die Daten in Form eines
invertierten Index auf einen externen Datenträger und liest diesen beim Start der Software in
den Hauptspeicher ein. Suchabfragen erfolgen daher immer auf einen Index der sich im
Hauptspeicher befindet. Auch das Speichern und Suchen von heterogenen Datenstrukturen
wie Produktdaten und Webseiten ist möglich.
4
Anhand einer Beispielanwendung wurde der Einsatz des Prototyps gezeigt und dessen
Geschwindigkeit mittels Load- und Perfomancetests geprüft.
1.4 Gliederung der Diplomarbeit
Kapitel 2
Kapitel 2 gibt einen Überblick über verschiedene Ansätze für fehlertolerantes Suchen. Es
werden fehlertolerante Algorithmen beschrieben und deren Vor- und Nachteile im Hinblick
auf den Einsatz in einer fehlertoleranten Suchsoftware herausgearbeitet.
Kapitel 3
In diesem Kapitel werden diverse Indizes beschrieben, verglichen und deren Eignung für
einen Einsatz in der zu implementierenden Suchsoftware, geprüft. Ein besonderes Augenmerk
wird dabei auf den benötigten Speicherplatz der einzelnen Indizes gelegt.
Kapitel 4
In Kapitel 4 werden zwei Anwendungsszenarien, für eine fehlertolerante Suche in Online-
Shops dargestellt. Aus diesen beiden Szenarien wurden anschließend funktionale und nicht
funktionale Anforderungen abgeleitet. Auf Grundlage der in Kapitel 4 definierten
Anforderungen wurde der Prototyp entwickelt und der fertig gestellte Prototyp auf funktionale
Vollständigkeit geprüft.
Kapitel 5
Dieses Kapitel beschreibt das Suchframework Lucene. Zudem werden notwendige
Modifikationen und Erweiterungen des Frameworks erhoben, um einen funktional
vollständigen Prototyp zu erhalten.
Kapitel 6
Kapitel 6 befasst sich mit der Implementierung des Prototyps. Es wird ein kurzer Überblick
über die verwendeten Werkzeuge, Bibliotheken und Frameworks gegeben und die wichtigsten
Komponenten des erstellten Systems erläutert. Zudem wird in diesem Kapitel der Einsatz des
Prototyps, anhand einer Beispielapplikation mit realen Produktdaten, gezeigt.
5
Kapitel 7
In diesem Kapitel werden die wesentlichsten Punkte der Diplomarbeit zusammengefasst und
ein Ausblick auf weiterführende Arbeiten gegeben.
6
2 Fehlertolerante Suchalgorithmen
Inhalt
Überblick
Phonetische Algorithmen
Soundex
Phonix
Double Metaphone
Berechnen der Ähnlichkeit zweier Zeichenketten
Levenshtein Algorithmus
Automatensuche
Bit-Parallelismus
Filterungsalgorithmen
Q-Gramme/N-Gramme
Dieses Kapitel beschreibt verschiedene Ansätze für fehlertolerantes Suchen. Der Zweck
dieses Kapitel ist ein Grundwissen über die Funktionsweise fehlertoleranter Algorithmen zu
schaffen, sowie ihre Einsatzmöglichkeiten zu zeigen, um eine ausreichende
Entscheidungsgrundlage für die Planung und Implementierung des Prototyps zu erlangen.
2.1 Überblick
Fehlertolerante Suchalgorithmen werden grundsätzlich in zwei Kategorien eingeteilt. Der
ersten Kategorie werden phonetische Algorithmen zugeordnet, welche auf die Aussprache
von Wörtern Rücksicht nehmen. Algorithmen der zweiten Kategorie messen die Ähnlichkeit
zweier Zeichenketten, indem sie entweder eine so genannte Editierdistanz berechnen oder
7
indem sie die Anzahl an gleichen Teilzeichenketten, welche als Q-Gramme oder auch als N-
Gramme bezeichnet werden, ermitteln.
Der Zweck phonetischer Algorithmen ist in einem Text t jene Wörter zu finden, die ähnlich
wie der Suchbegriff s betont und ausgesprochen werden. Sinnvoll ist die Anwendung von
phonetischen Algorithmen, wenn der Benutzer nicht weiß wie der gesuchte Begriff
geschrieben wird. Sucht ein Benutzer zum Beispiel nach Playstation tippt jedoch Playsteschn
als Suchbegriff ein, so sollte ein phonetischer Algorithmus erkennen, dass beide Wörter
ähnlich betont und ausgesprochen werden.
Algorithmen welche die Editierdistanz zwischen zwei Zeichenketten ermitteln, berechnen die
Anzahl der nötigen Operationen, um eine Zeichenkette s1 in eine Zeichenkette s2 zu
transformieren. Editieroperationen setzen sich aus dem Einfügen, Ersetzen, Löschen und
Austauschen von Buchstaben zusammen. Um zum Beispiel den Suchbegriff Kraswate in
Krawatte umzuwandeln sind zwei Editieroperationen nötig. Eine Operation, um den
Buchstaben s in s1 zu löschen und eine Operation, um den Buchstaben t in s1 einzufügen.
Q-Gramm oder N-Gramm basierende Algorithmen unterteilen ein Wort in Zeichenketten mit
der Länge q. Zum Beispiel würde der Begriff Waschmaschine mit der Länge q=2 in die Q-
Gramme WA, AS, SC, CH, HM, MA, AS, HI, IN, NE unterteilt werden. Die Ähnlichkeit zweier
Wörter wird durch die Anzahl an gleichen Q-Grammen bestimmt.
2.2 Phonetische Algorithmen
2.2.1 Soundex
Der erste phonetische Algorithmus mit der Bezeichnung Soundex [NARA00, Knut73] wurde
von Robert C. Russell und Margaret K. Odell entwickelt und 1918 patentiert. Der
Algorithmus erstellt zuerst aus jedem Wort einen vierstelligen Code und vergleicht
anschließend den Code des Suchbegriffs mit den Codes der Wörter im Text. Wird nun der
8
Suchbegriff und ein Wort im Text durch den gleichen Code dargestellt, so wird angenommen,
dass es zwischen den beiden Wörtern eine phonetische Übereinstimmung gibt.
Der Code des Wortes wird anhand einer kleinen Anzahl an Regeln erstellt. Für die erste Stelle
des Codes wird der erste Buchstabe des zu codierenden Wortes verwendet. Die Vokale A, E,
I, O und U sowie die Konsonanten Y, H und W werden für die Codierung nicht beachtet. Die
restlichen Buchstaben sind in Gruppen eingeteilt wobei jede Gruppe durch eine Ziffer
repräsentiert wird.
Ziffer Buchstabengruppe1 B, F, P, V2 C, G, J, K, Q, S, X, Z3 D, T4 L5 M, N6 R
Tabelle 1 zeigt die Buchstabengruppen des Soundexalgorithmus
Wie in Tabelle 2 dargestellt ergibt der Begriff Receiver den Code R216. Zeichenketten die
einen längeren Code ergeben, werden nur durch die ersten vier Stellen dargstellt und zu kurze
Codes werden durch Nullen ergänzt. Zum Beispiel wird das Wort Hose durch den Code H200
repräsentiert, da die Vokale o und e nicht beachtet werden. Stehen zwei oder mehrere
Buchstaben der gleichen Buchstabengruppe hintereinander so werden diese nur durch eine
Ziffer abgebildet.
R E C E I V E RR - 2 - - 1 - 6
Tabelle 2 stellt den Soundexcode für den Begriff Receiver dar
Beispiele für eine phonetische Übereinstimmung nach Soundex sind Mayer und Maier, die
jeweils den Code M600 ergeben oder die Begriffe Display und Disbley die auf den Code
D214 abgebildet werden.
Der Soundex Algorithmus ist jedoch nicht besonders zuverlässig, so würden zum Beispiel die
Begriffe Haus, Hose und Heike, welche keine phonetische Übereinstimmung aufweisen, den
Code H200 ergeben. Ein weiterer Nachteil des Algorithmus ist die Beschränkung des Codes
9
auf 4 Zeichen, dadurch wird bei längeren Wörtern mit gleichem Präfix derselbe Code
gebildet. Die Begriffe Druckerpatrone und Druckerkabel würden in Soundex somit durch den
Code D626 repräsentiert.
Mittlerweile gibt es zahlreiche weiterentwickelte Algorithmen. Eine wesentlich bessere
Alternative zu Soundex stellen die phonetischen Algorithmen Double Metaphone und Phonix
dar.
2.2.2 Phonix
Der weniger bekannte Phonix [Gadd88, Gadd90] Algorithmus versucht durch
Berücksichtigung von Ausspracheregeln, die Ergebnisse des Soundex Algorithmus zu
verbessern. Wie bei Soundex werden die Buchstaben in Buchstabengruppen eingeteilt und der
erste Buchstabe für die erste Stelle des Codes verwendet. Jedoch existieren für den ersten
Buchstaben die Ausnahmen das W und H ignoriert werden und die Buchstaben A, E, I, O, U,
Y durch V ersetzt werden. Im Wortinneren werden Vokale, doppelte Konsonanten und die
Buchstaben W, H und Y ignoriert. Im Gegensatz zu Soundex wird das Wort erst nach
Anwendung von 100 Ersetzungsregeln codiert. In diesen Ersetzungsregeln werden nicht nur
Buchstaben, sondern auch Buchstabenzusammensetzungen betrachtet und entsprechend der
Regel durch neue Buchstaben ersetzt. So wird zum Beispiel Ph in Phone durch F ersetzt und
anschließend in den Code F500 konvertiert. Auch der Phonix Algorithmus beschränkt den
Code auf nur 4 Zeichen, was zum bereits beschriebenen Problem bei langen Zeichenketten
führt.
2.2.3 Double Metaphone
Double Metaphone [Lawr00] wurde im Jahr 2000 von Lawrence Phillips vorgestellt und ist
eine Weiterentwicklung seines 1990 publizierten Metaphone [Lawr90] Algorithmus. Der
Metaphone Code hat eine variable Länge und ist nicht wie in Soundex auf vier Stellen
beschränkt. Eine Verbesserung der Suchergebnisse wird wie in Phonix durch die
Rücksichtnahme auf Ausspracheregeln der englischen Sprache erreicht. Da jedoch auch der
Metaphone Algorithmus noch einige Schwächen aufwies entwickelte Lawrence Phillips den
10
Double Metaphone Algorithmus, der zwei Codes für Wörter erstellt, welche eine Aussprache
auf mehre Arten zulassen. Weitere Änderungen betreffen den ersten Buchstaben, der immer
als A codiert wird, wenn dieser ein Vokal ist. Die Buchstaben Y und W werden ignoriert, und
die Buchstaben B und P werden nicht mehr separat codiert.
2.3 Berechnen der Ähnlichkeit zweier Zeichenketten
Im Folgenden werden grundlegende Algorithmen beschrieben, die die Ähnlichkeit zweier
Zeichenketten s1 und s2 berechnen, bzw. einen Suchbegriff s mit einer maximalen Anzahl an
k Fehlern in einem Text t finden. Algorithmen dieser Kategorie eignen sich um auf fehlerhafte
Eingaben, die durch Tippfehler entstehen, tolerant zu reagieren.
Zu Beginn wird der Algorithmus von Levenshtein [Leve65, Leve66] beschrieben, der auf
einfache Weise eine Editierdistanz zwischen zwei Zeichenketten berechnet. Anschließend
wird auf Algorithmen eingegangen, die eine bessere Laufzeitkomplexität und einen
geringeren Speicherbedarf aufweisen.
Tabelle 3 stellt eine Übersicht über die im Text verwendeten Symbole dar.
s gesuchte Zeichenkette
t zu durchsuchender Text
m = | s | Länge von s
n = | t | Länge von t
k Anzahl benötigter Editieroperationen um s in t zu transformieren
= k/m Fehlerquotient
w Anzahl der Bits mit denen eine CPU arbeitet, normalerweise 32 oder 64
ε leere Zeichenkette
∑ Alphabet, z.B. deutsches Alphabet, ASCII Zeichensatz oder Binäralphabet
Tabelle 3 Definition der im Text verwendeten Symbole
2.3.1 Levenshtein Algorithmus
11
Der Levenshtein Algorithmus wurde erstmals 1965 von dem russischen Wissenschaftler
Vladimir Levenshtein vorgestellt. Der Algorithmus berechnet die Ähnlichkeit von zwei
Zeichenketten, indem er die minimale Anzahl an benötigten Editieroperationen berechnet, um
eine Zeichenkette s1 in eine Zeichenkette s2 zu transformieren. Editieroperationen bestehen
aus dem Einfügen, Löschen und Ersetzen von Zeichen. Zum Beispiel kann das Wort Husen,
mit zwei Operationen, an das Wort Hose angepasst werden, indem das Zeichen u ersetzt und
das Zeichen n im Wort Husen gelöscht wird.
Im ersten Schritt des Algorithmus wird ein Array d erstellt, dass 0 bis m Reihen und 0 bis n
Spalten enthält. Die erste Reihe wird mit 0 bis n und die erste Spalte mit 0 bis m initialisiert.
H O S E0 1 2 3 4
H 1U 2S 3E 4N 5
Tabelle 4 Initialisierter Array für die Berechnung der Editierdistanz zwischen den Wörtern Hose und Husen.
Nach der Initialisierung werden die Reihen i = 1 bis m in den Spalten j = 1 bis n durchlaufen
und der Wert für die aktuelle Zelle durch folgende Vorschrift ermittelt. Der Wert der Zelle
d[i, j] berechnet sich aus dem Minimum der Zelle d[i-1, j]+1, der Zelle d[i, j-1]+1 und der Zelle
d[i-1, j-1]+Kosten. Die Kosten betragen 0, wenn s[i] gleich t[j] ist, ansonsten betragen die
Kosten 1. Der Wert in der Zelle d[n, m] drückt die Editierdistanz zwischen den beiden
Wörtern aus.
Berechnung der 1. Spalte Berechnung der 2. Spalte
12
Berechnung der 3. Spalte Berechnung der 4. Spalte
Tabelle 5 zeigt die Berechnung der Editierdistanz mittels Levenshtein – Algorithmus. Der fett gedruckte Wert in der letzten Zeile der 4. Spalte drückt die Distanz zwischen den beiden Wörtern aus.
Wie in Tabelle 5 gezeigt wurde kann das Wort Husen durch zwei Operationen an das Wort
Hose angepasst werden, da der Wert in d[n,m] = d[5,4] zwei beträgt.
Für den Austausch zweier angrenzender Buchstaben benötigt der Levenshtein Algorithmus
zwei Operationsschritte. Die Wörter Hsoe und Hose haben daher eine Levenshtein Distanz
von 2, da zwei Ersetzungen vorgenommen werden müssen. Damit der Algorithmus den
Austausch zweier angrenzender Buchstaben als eine Editieroperation zählt, ist es nötig eine
weitere Regel hinzuzufügen. Die Zelle d[i, j] kann auch durch d[i-2, j-2]+1 berechnet werden
wenn s[i-1] = t[j] und s[i] = t[j-1] ist. [LoWa75]
Mit dem gezeigten Algorithmus ist es nicht möglich eine approximative Suche von
Teilzeichenketten durchzuführen. Eine Suche nach Hosn im Text Jeanshose würde zu keinem
erfolgreichen Suchergebnis führen, da die Anzahl der Editieroperation zu groß ist. Dieses
Problem lässt sich jedoch lösen, in dem der Algorithmus etwas angepasst wird. Der
Unterschied zum vorhin beschriebenen Verfahren besteht darin, dass im modifizierten
Algorithmus jede Position in t der potentielle Anfang eines Treffers ist. Somit ist es nötig d[0,
Tabelle 6 Der dynamische Programmieralgorithmus für die Suche nach Hosn im Text Jeanshose. Fett markierte Einträge zeigen einen Treffer mit einem Fehler an.
Die Laufzeitkomplexität des ursprünglichen Levenshtein Algorithmus beträgt O(mn) und der
Speicherbedarf beträgt O(m). Seit der Veröffentlichung des Levenshtein Algorithmus gab es
jedoch zahlreiche Verbesserungen hinsichtlich Laufzeit und Speicherbedarf, wie zum Beispiel
bit-parallele Algorithmen oder Filterungsalgorithmen.
2.3.2 Automatensuche
Da bit-parallele Algorithmen die Funktionsweise von Automaten simulieren, wird im
Folgenden ein Überblick über das Konzept von Automaten gegeben. Auf eine detaillierte
Beschreibung der Algorithmen wurde jedoch verzichtet, da die nachfolgend beschriebenen
bit-parallelen Algorithmen, dieselben Eigenschaften wie Automaten haben, jedoch eine
geringere Laufzeitkomplexität aufweisen.
Die approximative Suche mittels finiter/endlicher Automaten wurde erstmals 1985 von Esko
Ukkonen [Ukko85] vorgestellt.
Finite Automaten beschreiben ein mathematisches System mit diskreten Ein- und Ausgaben.
Das modellierte System verfügt dabei über eine begrenzte Anzahl an Zuständen. Der aktive
Zustand zu einem bestimmten Zeitpunkt, fasst Informationen über bereits verarbeitete
Eingaben zusammen. Ein gutes Beispiel für ein finites System ist der Kontrollmechanismus
eines Aufzuges. Der Mechanismus merkt sich keine Anfragen die bereits ausgeführt wurden,
er weiß jedoch in welchem Stock sich der Aufzug befindet, in welche Richtung er sich bewegt
(rauf oder runter) und welche Anfragen noch auszuführen sind. [HoUl79]
Es gibt zwei unterschiedliche Typen von finiten Automaten, deterministische und
nichtdeterministische. Deterministische finite Automaten (DFA) lassen jeweils nur einen
Zustandsübergang zu, bei nichtdeterministischen finiten Automaten (NFA) sind hingegen
mehrere Zustandsübergänge möglich. Ein Zustandsübergang ist ein Wechsel von einem
Zustand q1 in einen anderen Zustand q2.
14
Abbildung 1 Das Diagramm auf der linken Seite stellt einen deterministischen finiten Automaten dar, das rechte Diagramm zeigt einen nichtdeterministischen finiten Automaten. Beide Diagramme haben q3 als Endzustand
definiert. Wenn ein zu durchsuchender Text t als Eingabe dient und der Buchstabe b eingelesen wird dann befindet sich der DFA im Zustand q2, der NFA hat jedoch nach Einlesen von b zwei aktive Zustände q0 und q2
Der von Ukkonen beschriebene Automat ist in deterministischer Form. Eine
nichtdeterministische Lösung für die Berechnung der Editierdistanz stellte Byeza-Yeates
[Byez91] 1991 vor.
Abbildung 2 NFA für den Suchbegriff Pulower mit maximal zwei Fehlern. Die gestreiften Zustände sind aktiv nachdem die Buchstaben P und U eingelesen wurden.
Abbildung 2 zeigt den Suchbegriff Pulower in Form eines NFA, welcher jene Zeichenketten
in t findet, die durch maximal zwei Editieroperationen an s angepasst werden können. Die
erste Reihe wird für eine Suche ohne Fehler benötigt. Die zweite Reihe dient der Suche nach
Zeichenketten mit einem Fehler und die dritte Reihe für die Suche nach Zeichenketten mit
zwei Fehlern. Horizontale Zustandsübergänge bedeuten, dass das eingelesene Zeichen mit
dem aktuellen Zeichen im Suchbegriff übereinstimmt. Diagonale und vertikale
Zustandsübergänge stellen eine Editieroperation dar. Muss ein Buchstabe des Suchbegriffs
durch ein anderes Zeichen ersetzt werden, so wird dies durch einen diagonalen
15
Zustandübergang mit dem Zeichen ∑ ausgedrückt. ∑ steht dabei für einen beliebigen
Buchstaben des verwendeten Alphabetes. Eine Löschoperation wird durch das Zeichen ε
gekennzeichnet, welches für eine leere Zeichenkette steht. Ein vertikaler Zustandsübergang
wiederum steht für eine Einfügeoperation im Suchbegriff. Auch dieser Zustandsübergang ist
mit ∑ beschriftet. Eine Editieroperation wird daher immer mit einem Zustandsübergang in
eine darunter liegenden Reihe ausgedrückt. Abbildung 2 weist drei mögliche Endzustände
auf. Ist einer der drei Endzustände aktiv so wurde ein Treffer gefunden. Ein aktiver
Endzustand der ersten Reihe bedeutet, dass ein Treffer ohne Fehler gefunden wurde. Ein
aktiver Endzustand der zweiten Reihe bedeutet, dass eine Übereinstimmung mit genau einem
Fehler gefunden wurde usw.
Der von Ukkonen vorgestellte Algorithmus benötigt einen Speicherplatz von O(min(3m,
m(2mσ)k)). Der Algorithmus ist daher nur für sehr kurze Suchbegriffe und einer niedrigen
Anzahl an maximal erlaubten Fehlern praktikabel.
Obwohl einige Verbesserungen und Weiterentwicklungen des ursprünglichen Algorithmus
existieren, ist die Simulation eines NFA mittels Bit-Parallelismus ein besserer Lösungsansatz,
da diese eine geringere Laufzeitkomplexität aufweisen.
2.3.3 Bit-Parallelismus
Die Grundidee dieser Art von Algorithmen, ist einen nichtdeterministischen Automaten oder
Algorithmus der dynamischen Programmierung, zu parallelisieren. Bit-Parallele Algorithmen
nutzen dabei die parallele Verarbeitung des Computers aus. Moderne Computer führen
Rechenoperationen mit 32 oder 64 Bit aus. Die Anzahl der Operationen, die ein Algorithmus
durchführt, kann durch die parallele Verarbeitung des Computers bis zu einem maximalen
Faktor w reduziert werden, wobei w die Anzahl der Bits ausdrückt. [Nava01]
Der Shift-Or [BaYa92] Algorithmus ist für schnelles exaktes Suchen von Zeichenketten
geeignet. Mit diesem Algorithmus ist es daher nur möglich Zeichenketten mit null Fehlern zu
finden. Da er jedoch die Basis für nachfolgende approximative Suchalgorithmen bildet, wird
er im Folgenden vorgestellt.
16
Der Shit-Or Algorithmus simuliert einen NFA indem er dessen Zustandsübergänge
parallelisiert.
Abbildung 3 Nichtdeterministischer Automat der nach Disc ohne Fehler sucht.
Zum besseren Verständnis wird der Shift-And Algorithmus beschrieben. Diesen haben Baeza-
Yates und Gonnet in den Shift-Or Algorithmus konvertiert, da das Auffüllen mit 1 bei
Schiebeoperationen in der Programmiersprache C nicht möglich ist.
Der Algorithmus erstellt einen Bitvektor R mit der Länge m, in welchem der aktuelle
Suchfortschritt gespeichert wird. Auch für jedes Zeichen c des Alphabetes ∑wird ein Vektor
angelegt. Der Vektor speichert die Positionen von c im Suchbegriff. Der Bitvektor VD für den
Suchbegriff Disc hat somit die Bitfolge 1000 und Vektor VI die Bitfolge 0100 usw.
Die Bits des Vektors R0 werden mit 0 initialisiert. Die hochgestellte 0 in R0 steht für die
Anzahl der Fehler. R0 dient daher der Suche nach Zeichenketten mit 0 Fehlern. R0’ wird durch
eine bitweise Verschiebung in R0 nach rechts, welche mit eins aufgefüllt wird, sowie einer
anschließenden UND Operation mit dem Vektor des eingelesenen Zeichens, ermittelt. Eine
Übereinstimmung des Musters in einem Text liegt dann vor, wenn R0’m gleich 1 ist.
VD VI VS VK Vsonst
1000 0100 0010 0001 0000
Tabelle 7 zeigt die Vektoren des Suchbegriffes Disk. Die Position des Buchstaben im Wort wird im Vektor durch eine 1 ausgedrückt. Jene Buchstaben die nicht im Suchbegriff vorkommen, werden durch den Vektor Vsonst
repräsentiert, welcher nur Nullen enthält.
Im Folgenden wird die Anwendung des Shift-And Algorithmus anhand des Suchbegriffs Disk
im Text Harddisk gezeigt.
1 Initialisierung des Zustandsvektors R 0000
2 Bitweise Verschiebung des Zustandsvektors nach rechts
1000
3 Bitweise UND Operation mit Vektor von 1000 Zustandsvektor
17
Zeichen H. Da der Suchbegriff das Zeichen H nicht enthält wird der Vektor Vsont für die UND Operation verwendet.
0000 Vektor sontige 0000 neuer Zustandsvektor
4 Bitweise Verschiebung nach rechts 1000
5 Bitweise UND Operation mit Vektor von Zeichen A (Vsont)
0000 (neuer Zustandsvektor)
6 Bitweise Verschiebung nach rechts 1000
7 Bitweise UND Operation mit Vektor von Zeichen R
0000
8 Bitweise Verschiebung nach rechts 1000
9 Bitweise UND Operation mit Vektor von Zeichen D
1000
10 Bitweise Verschiebung nach rechts 1100
11 Bitweise UND Operation mit Vektor von Zeichen D
1000
12 Bitweise Verschiebung nach rechts 1100
13 Bitweise UND Operation mit Vektor von Zeichen I
0100
14 Bitweise Verschiebung nach rechts 1010
15 Bitweise UND Operation mit Vektor von Zeichen S
0010
16 Bitweise Verschiebung nach rechts 1001
17 Bitweise UND Operation mit Vektor von Zeichen K
0001 (Treffer im Text Harddisk)
Tabelle 8 zeigt die exakte Suche von Disk im Text Harddisk, die durch eine bitweise Verschiebung in R0, sowie einer UND Operation mit dem jeweiligen Buchstabenvektor, realisiert wird. R0’17 zeigt einen Treffer mit null
Fehlern an, da dass letzte Bit auf eins gesetzt ist.
Im Unterschied zum Shift-And Algorithmus, speichert der Shift-Or Algorithmus die
Bitmuster der Zeichen in umgekehrter Reihenfolge und kennzeichnet die Positionen in denen
das Zeichen vorkommt mit einer 0, alle anderen mit einer 1 (VD = 11110). Vektor R wird mit
R0i = 1, 1 ≤ i ≤ m initialisiert, bitweise nach links verschoben und mit einer 0 aufgefüllt. Durch
einen anschließenden OR Vergleich von Vt und R wird R’ ermittelt. Eine Übereinstimmung
des Musters ist gegeben, wenn R0’1 = 0 ist.
In [WuMa92] zeigen Wu und Manber wie der Shift-Or Algorithmus zu einem approximativen
Suchalgorithmus erweitert werden kann. Die Idee liegt in der Simulation eines NFA, wie er
zum Beispiel in Abbildung 2 dargestellt wurde, mittels bitparalleler Operationen. Die
Erweiterung wird anhand des Basisalgorithmus Shift-And beschrieben, da dies verständlicher
ist.
18
Wu und Manber verwenden 0 bis k Arrays für R, welche jeweils für die Berechnung der
aktiven Zustände benötigt werden. Der Vektor R0 entspricht der ersten Reihe eines NFA. Er
dient daher zur exakten Suche von s in t. Der Vektor R1 wiederum simuliert die zweite Reihe
des Automaten usw. Zudem wird wie in Tabelle 6, ein Vektor für jedes Zeichen des
Suchbegriffes erstellt, um die Positionen der Buchstaben im Suchbegriff zu kennzeichnen. Ein
Treffer im Text mit maximal k Fehlern liegt dann vor, wenn der Zustandsvektor R0j [m] = 1
bzw. Rkj [m] = 1 ist. Für jede Editieroperation wird nun gezeigt wie der Übergang von R1
j-1 zu
R1j berechnet wird.
Angenommen der Algorithmus lässt nur Einfügeoperationen zu, so gibt es eine
Übereinstimmung der ersten i Zeichen des Musters mit den letzten i+1 bis j Zeichen des
Textes, falls Rij [i] = 1 ist.
Es gibt zwei Fälle in welchem der Suchbegriff bis zu Zeichen i mit maximal einem Fehler mit
den Zeichen tj+1 übereinstimmt. Der erste Fall trifft dann zu wenn die ersten i Zeichen bis tj
übereinstimmen. Wird nun ein Zeichen im Suchbegriff eingefügt so gibt es eine
Übereinstimmung mit einer Einfügeoperation bis zu tj+1. Im zweiten Fall gibt es eine
Übereinstimmung der ersten i-1 Zeichen bis tj. Dies bedeutet, dass bereits innerhalb des
Suchbegriffes ein Buchstabe eingefügt wurde und das Zeichen tj+1 gleich si sein muss, damit
eine Übereinstimmung gegeben ist.
Im ersten Fall genügt es den Wert von R0j einfach nach R1
j+1 zu kopieren. Für den zweiten Fall
ist eine Verschiebung des Bitmusters R1j nach rechts und eine AND Operation mit Vt+1 nötig.
Die Berechnungsvorschrift für Rdj+1 lautet daher Rd-1
j OR RShift[Rdj] AND Vt+1.
R01 R0
2 R03 R0
4 R05
H O U S E1 0 0 0 00 1 0 0 00 0 0 0 00 0 0 0 0
Tabelle 9 zeigt Vektor R0 bei einem Vergleich von Suchbegriff HOSE mit dem Text HOUSE.
R11 R1
2 R13 R1
4 R15
H O U S E1 1 0 0 00 1 1 0 00 0 0 1 00 0 0 0 1
Tabelle 10 zeigt Vektor R1 bei einem Vergleich von Suchbegriff HOSE mit dem Text HOUSE mit
maximal einer Einfügeoperation.
Tabelle 10 zeigt einen Treffer des Suchbegriffes Hose im Text House mit maximal einer
Einfügeoperation, da das letzte Bit in Vektor R15 auf eins gesetzt ist. Zur näheren Erläuterung
wird die Berechnung von Vektor R13 erklärt. Mit R1
3 wird der Zustandsvektor R nach dem
Einlesen des dritten Zeichens bezeichnet, der maximal eine Einfügeoperation beinhaltet. Für
19
die Berechnung von R1 wird der Vektor R0 sowie der Vektor Vt benötigt. Der Zustandsvektor
R0 wird wie bereits erwähnt, für exaktes Suchen verwendet, also zur Suche nach
Zeichenketten die keine Fehler beinhalten. Vt steht für den Vektor, der die Positionen des
eingelesenen Zeichens im Suchbegriff beinhaltet. Laut Berechnungsvorschrift ist R13 gleich
R02 OR RShift[R1
2] AND Vt=U. Der Vektor VU ist gleich 0000 da das Zeichen U nicht im
Suchbegriff vorkommt. Für R13 ergibt sich folgende Berechnung. R1
3 = 0100 OR RShift[1100]
AND 0000 = 0100 OR 0110 AND 0000 = 0100 OR 0000 = 0100.
Ist nur das Löschen eines Zeichens erlaubt so ist eine Übereinstimmung gegeben wenn die
ersten i-1 Zeichen des Suchbegriffes exakt bis zu tj+1 übereinstimmen. Dies entspricht einem
Löschen von Zeichen pi und einer Übereinstimmung der ersten i-1 Zeichen. Für den zweiten
Fall gilt, wenn die ersten i-1 Zeichen bis zu tj übereinstimmen, wurde bereits ein Zeichen im
Suchbegriff gelöscht und tj+1 muss gleich pi sein damit ein Treffer mit k=1 erzielt wird.
Für den ersten Fall ist eine Verschiebung des Wertes Rj+1 nach rechts nötig. Die
Berechnungsvorschrift für den zweiten Fall entspricht der Berechnungsvorschrift des zweiten
Falles für das Einfügen eines Buchstaben. Für Rdj+1 ergibt sich somit RShift(Rd-1
j+1) OR
RShift[Rdj] AND Vt+1.
R01 R0
2 R03 R0
4
H O S E1 0 0 00 1 0 00 0 0 00 0 0 00 0 0 0
Tabelle 11 zeigt Vektor R0 bei einem Vergleich von Suchbegriff HOUSE mit HOSE.
R11 R1
2 R13 R1
4
H O S E1 1 1 11 1 0 00 1 0 00 0 1 00 0 0 1
Tabelle 12 zeigt Vektor R1 bei einem Vergleich von Suchbegriff HOSE mit HOUSE mit maximal einer
Löschoperation.
Auch für die Ersetzung eines Zeichens gibt es zwei Möglichkeiten. Im ersten Fall gibt es eine
exakte Übereinstimmung der ersten i-1 Zeichen bis zu tj. Dieser Fall entspricht dem Ersetzen
eines Zeichens pi durch tj+1 sowie einer Übereinstimmung der ersten i-1 Zeichen. Im zweiten
Fall wurde bereits ein Zeichen im Suchbegriff ersetzt. Die ersten i-1 Zeichen stimmen mit
einer Ersetzung bis zu tj überein. tj+1 muss somit gleich pi sein damit eine Übereinstimmung
möglich ist. Der zweite Fall wird wie schon vorhin durch eine Verschiebung von R1j nach
rechts und einem AND mit Vj+1 abgedeckt. Für den ersten Fall ist eine Verschiebung von Rj
20
nötig. Dies entspricht einer Betrachtung von Rj[i-1]. Rdj+1 wird durch RShift(Rd-1
j) OR
RShift[Rdj] AND Vt+1 berechnet.
H O S E1 0 0 00 0 0 00 0 0 00 0 0 0
Tabelle 13 zeigt Vektor R0 bei einem Vergleich von Suchbegriff HUSE mit HOSE.
H O S E1 1 1 10 1 0 00 0 1 00 0 0 1
Tabelle 14 zeigt Vektor R1 bei einem Vergleich von Suchbegriff HUSE mit HOSE mit maximal einer
Ersetzungsoperation.
Für alle drei Editieroperationen gilt zusammenfassend: Rdj+1 = (RShift[Rd
j] AND Vt+1) OR Rd-1j
OR RShift(Rd-1j+1) OR RShift(Rd-1
j). Dies kann weiter vereinfacht werden zu Rdj+1 = (RShift[Rd
j]
AND Vt+1) OR Rd-1j OR RShift(Rd-1
j+1 OR Rd-1j).
2.3.4 Filterungsalgorithmen
Algorithmen, die auf dem Konzept der Filterung von Text basieren, verwerfen jene Teile
eines Textes, die nicht mit dem Teilmuster eines Suchbegriffes übereinstimmen. Der
Suchbegriff wird in k+1 Teile zerlegt, somit kann eine exakte Suche nach mindestens einem
Teilmuster durchgeführt werden. Textstellen die als potentielle Übereinstimmung erkannt
wurden, müssen zudem mit einem approximativen Suchalgorithmus verifiziert werden. Wird
z.B.: nach dem Begriff Taschenrechner mit maximal k=1 Fehler in einem Text gesucht, so
muss entweder der Teilbegriff Taschen oder der Teilbegriff rechner mit k=0 Fehlern im Text
vorkommen, da ein Fehler in beiden Teilbegriffen k=1 überschreiten würde.
Filterungsalgorithmen arbeiten sehr schnell bei einem kleinen Fehlerquotienten = k/m. Für
approximative Suchen mit einem hohen Fehlerquotienten sind Filterungsalgorithmen nicht
sinnvoll, da der Suchbegriff in viele kurze Teilbegriffe unterteilt wird und es daher eine große
Anzahl an potentiellen Treffern gibt, die nochmals mit einem approximativen
Suchalgorithmus überprüft werden müssen.
Ein relativ einfacher Filterungsalgorithmus wurde von Wu und Manber [WuMa92] 1992
vorgestellt. Sie teilen den Suchbegriff in k+1 Teile und verwenden anschließend einen
modifizierten Shift-Or Algorithmus mit welchem die Teilbegriffe parallel gesucht werden.
21
Die parallele Suche wird realisiert indem sie die Zeichen der einzelnen Teilbegriffe
hintereinander reihen und das Bitmuster, um k+1 Stellen, verschieben. Zum Beispiel wird der
Begriff Taschenrechner mit k=3 in die Teilbegriffe tasch, enrec, hner aufgeteilt. Durch die
Aneinanderreihung der einzelnen Buchstaben aus den Teilbegriffen wird der Suchbegriff
tehannsrecerhc für den modifizierten Shift-Or Algorithmus gebildet. Ein Treffer eines
Teilbegriffes liegt vor, wenn einer der letzten k Bits in R gleich 0 ist. Da für die parallele
Suche keine zusätzlichen Operationen durchgeführt werden müssen ist sie genauso schnell
wie die Suche nach nur einem Suchbegriff.
2.3.5 Q-Gramme/N-Gramme
Die unscharfe Suche mittels Q-Gramme oder auch N-Gramme genannt, ist eine einfache
Methode zwei Zeichenketten zu vergleichen. Die beiden Begriffe werden jeweils in
Teilzeichenketten der Länge q geteilt. Dabei entsteht eine Menge, welche sich aus Q-
Grammen zusammensetzt, die sowohl im Suchbegriff s als auch im Text t vorkommen sowie
Q-Gramme, welche nur in einer der beiden Zeichenketten vorkommen.
Q-Gramme Text Suchbegriff
Jacke Jake
ja X X
ac X
ck X
ke X X
ak X
Tabelle 15: Q-Grammvergleich der Wörter Jacke und Jake mit einer Länge q=2.
Die Ähnlichkeit zwischen s und t ist durch die gemeinsame Gramm-Anzahl(s, t) = |Gs ∩ Gt|
gegeben. Die Ähnlichkeit zwischen Jacke und Jake, mit q=2 ist somit 2, da beide Begriffe die
Gramme ja und ke beinhalten. Bei dieser Berechnung wird die Buchstabenreihenfolge nicht
beachtet, da jedoch die meisten Wörter keine Q-Gramme beinhalten, die wiederholt auftreten,
kann dies vernachlässigt werden. [ZoDa95]
Einfach nur die Anzahl gleicher Q-Gramme von s und t zu zählen reicht für die Suche nach
ähnlichen Zeichenketten nicht aus, da auf unterschiedliche Zeichenkettenlängen nicht
eingegangen wird. So hätte ein Vergleich von Hose mit sich selbst dieselbe Gramm-Anzahl
22
wie ein Vergleich von Hose mit Hosenanzug. Ukonnen [Ukko92a] schlägt daher die
Berechnung eines Gramm-Abstandes vor, der durch die Anzahl der ermittelten Q-Gramme
aus dem Suchbegriff sowie dem zu vergleichenden Wort im Text, abzüglich der gemeinsamen
Q-Gramme berechnet wird. Der Gramm-Abstand für q=2 zwischen Jacke und Jake beträgt
somit 3 und der Abstand von Hose und Hosenanzug beträgt 6. Wenn s und t einen
Editierabstand k nicht überschreiten sollen so müssen sie mindestens (max( |s|, |t| ) + q – 1) –
k * q gleiche Q-Gramme besitzen. [GrPa01] Für Jacke und Jake mit q=2 und maximal k=2
Fehlern ergibt dies eine Mindestanzahl an (max(5,4)+2-1)-2*2 = 2 Q-Grammen.
2.4 Fazit
Phonetische Algorithmen eignen sich nur beschränkt für den Einsatz in einer fehlertoleranten
Suchsoftware, da sie nicht besonders zuverlässig sind und dadurch die Qualität des
Suchergebnisses leidet. Sie sollten nur in Kombination mit einem weiteren Algorithmus
eingesetzt werden, welcher die Editierdistanz oder den Gram-Abstand zweier Zeichenketten
berechnet. Ein mögliches Anwendungsszenario wäre eine phonetische Suche immer dann
durchzuführen wenn der mit ihm eingesetzte Algorithmus, keinen Treffer im Text erzielen
konnte. Es gilt jedoch zu beachten, dass die hier beschriebenen phonetischen Algorithmen für
die englische Sprache entwickelt wurden und sie alle eine hohe Laufzeitkomplexität
aufweisen. Wird ein phonetischer Algorithmus eingesetzt so gilt es dem Double Methaphone
Algorithmus den Vorzug zu geben, da dieser durch eine variable Codelänge und einer großen
Anzahl von Ersetzungsregeln die wenigsten Schwächen aufweist.
Der ursprüngliche Levenshteinalgorithmus hat mit O(mn) eine relativ Hohe
Laufzeitkomplexität. Seine Vorteile liegen in der einfachen Implementierung und in der
Berechnung der erweiterten Editierdistanz, also den Austausch zweier angrenzender
Buchstaben als eine Operation zu zählen. Eine approximative Suche mit Shit-Or/Shift-And ist
mit O(k⌈m/w⌉ sehr schnell. Der Nachteil dieses Algorithmus ist jedoch, dass nur die einfache
Editierdistanz berechnet werden kann. Filterungsalgorithmen gehören zu den schnellsten
Algorithmen, solange der Fehlerquotient klein ist. Q-Gram/N-Gram basierende Algorithmen
können im Gegensatz zu den anderen Algorithmen auch Wortvariation finden, dazu benötigen
sie jedoch extra Speicherplatz. Für die Auswahl einer dieser Algorithmen gilt es daher die
Kriterien: Berechnung der erweiterten Editierdistanz, Geschwindigkeit, maximal mögliche
23
Größe des Fehlerquotienten, Suche von Wortvariationen und Speicherplatzverbrauch zu
gewichten.
24
3 Indexierungsmethoden
Inhalt
Invertierter Index
Trie
Patricia-Trie
Suffix-Trie
Suffix-Tree
Suffix-Array/PAT-Array
Fazit
In diesem Kapitel werden Indizes beschrieben, die häufig in der Praxis eingesetzt werden oder
eine Grundlage für weitere verbesserte Indexierungsmethoden darstellen. Jeder Index wird
hinsichtlich seiner Eignung für den Einsatz in einer fehlertoleranten Suchsoftware geprüft und
seine Einsatzbereiche, sowie seine Vor- und Nachteile erörtert.
Ein Index ist eine Datenstruktur, welche darauf ausgerichtet ist, die Verarbeitungs-
geschwindigkeit von Suchabfragen zu erhöhen. Es muss jedoch beachtet werden, dass Indizes
Speicherplatz sowie Zeit für ihre Erstellung benötigen. Die Verwendung eines Index ist nur
sinnvoll, wenn die Anzahl der Suchabfragen größer als die Anzahl der Änderungen des Index
ist, da nicht nur die Erstellung sondern auch die Aktualisierung eines Index ein Vielfaches der
Zeit einer Suchabfrage kostet [BaNa04].
Im Hinblick auf das Ziel dieser Diplomarbeit, eine fehlertolerante Suchsoftware für
Onlineshops zu implementieren, ist es zweckmäßig einen Index zu verwenden, da sich
Produktdaten zwar täglich ändern können, die Anzahl der Suchabfragen aber üblicherweise
weitaus größer ist als die Anzahl der Änderungen eines Index.
25
Für die Beispiele in diesem Kapitel gilt, dass zwischen Groß- und Kleinschreibung nicht
unterschieden wird. Für Indizes die durch eine Baumstruktur dargestellt werden, wurde
zusätzlich das Terminierungssymbol $ verwendet um ein Wortende zu kennzeichnen.
3.1 Invertierter Index
Ein invertierter Index speichert alle Wörter eines Textes und die Positionen ihres Auftretens
im Text in eine Liste.
1 5 10 18 22 29 38 42 47 55 59
Ein Text besteht aus vielen Wörtern. Ein Wort besteht aus Buchstaben.
Vokabular Positionen
aus 18, 55
besteht 10, 47
Buchstaben 59
ein 1, 38
Text 5
vielen 22
Wort 42
Wörtern 29
Abbildung 4 Ein Text und der dazugehörige invertierte Index
Die Suche in einem invertierten Index ist sehr einfach, da nur die Liste mit dem Vokabular
durchsucht werden muss und bei einem Treffer die dazugehörigen Positionen zurückgegeben
werden. Auch eine Suche mittels regulärer Ausdrücke sowie unscharfes Suchen ist möglich.
Dazu muss jedoch die ganze Liste durchlaufen und die einzelnen Wörter auf
Übereinstimmung geprüft werden.
Invertierte Indizes können in O(n) Zeit erstellt werden und benötigen ab einer bestimmten
Textgröße weniger Speicherplatz als der Text selbst. Baeza-Yates und Ribeiro-Neto [BaNe99]
zeigen, dass die Anzahl der Wörter in einem Text ab einer bestimmten Größe nur noch
sublinear mit der Textgröße steigt und die frei wählbare Größe ß in Heaps’ Law [Heap78]
26
üblicherweise zwischen 0,4 und 0,6 liegt. Heaps’ Law definiert die Vokabulargröße mit O(nß)
wobei ß ein positiver Wert kleiner 1 ist und n die Textlänge ausdrückt.
Abbildung 5 zeigt einen sublinearen Anstieg der Vokabulargröße zur Textgröße nach Heaps’ Law. Die X-Achse stellt die Textgröße dar, die Y-Achse zeigt die Vokabulargröße. Übernommen aus [Answ05]
Der invertierte Index eignet sich für schnelles exaktes Suchen und ist sehr einfach, zum
Beispiel durch einen Hashtable oder mittels einer sortierten Liste, zu implementieren. Als
Nachteil ist zu erwähnen, dass für eine approximative Suche sowie für eine Suche nach
Teilzeichenketten und regulären Ausdrücken das gesamte Vokabular durchlaufen werden
muss.
3.2 Trie
Die Trie Datenstruktur wurde erstmals 1959 von Renee de la Briandais [Brian59] publiziert.
1960 führte Edward Fredkin [Fred60] die Bezeichnung Trie ein, welche aus dem englischen
Begriff Retrieval abgeleitet wurde und wie try ausgesprochen wird.
Ein Trie ist ein Suchbaum in dem alle Teilzeichenketten, mit gleichem Präfix, an denselben
Knoten angehängt werden. Die internen Knoten des Baumes repräsentieren jeweils Zeichen
eines Präfixes und verlinken auf alle möglichen nachfolgenden Zeichen. In den Blättern des
Tries befinden sich die eigentlichen Informationen. Dies kann zum Beispiel die gesuchte
27
Zeichenkette, die Position der Zeichenkette im Text oder auch eine Liste von URLs sein,
welche den Suchbegriff beinhalten.
Abbildung 3 zeigt wie der Text Fischers Fritz fischt frische Fische in einem Trie gespeichert
wird.
Abbildung 6 Trie mit dem Text Fischers Fritz fischt frische Fische.
Sucht man im Trie von Abbildung 6 nach Fritz, so beginnt man bei der Baumwurzel, folgt der
F Kante, anschließend der R Kante, dann der I und der T Kante und zuletzt der Z Kante. Für
eine Suche nach Franz wird wieder von der Wurzel ausgegangen dann der F und R Kante
gefolgt, da es aber keine A Kante gibt, befindet sich der gesuchte Begriff nicht im Text.
28
Ein Trie kann auf verschiedene Arten implementiert werden. Im Folgenden wird anhand der
Wörter Fritz und fischt eine Implementierung mit Arrays, sowie durch eine verlinkte Liste,
gezeigt.
Abbildung 7 zeigt zwei Implementierungsmöglichkeiten eines Tries mit den Wörtern fischt und Fritz. Auf der linken Seite wird eine Implementierung durch Arrays dargestellt, auf der rechten Seite wird eine
Implementierung mittels einer verlinkte Liste gezeigt.
Eine Implementierung mittels Arrays ermöglicht einen schnellen Zugriff auf die einzelnen
Zeichen, hat jedoch den Nachteil, dass bei einem Index mit wenigen Wörtern viel Speicher
verschwendet wird, da die meisten Pointer auf Null zeigen. Die Laufzeit für die Suche einer
Zeichenkette beträgt im schlechtesten Fall O(m) wobei m für die Länge der längsten
Zeichenkette steht.
Tries werden unter anderem zur Rechtschreibprüfung oder als Indizes in Web-Suchmaschinen
verwendet. Auch für approximatives Suchen und für die Suche nach regulären Ausdrücken
können Tries verwendet werden. Ein regulärer Ausdruck beschreibt ein Muster mit Hilfe von
Symbolen. So kann zum Beispiel der reguläre Ausdruck (A+C)((B+C)D) für ABD, CBD,
ACD oder auch CCD stehen [Sedg92].
29
Der Trie Index ermöglicht eine sehr schnelle Suche. Eine Teilzeichenkettensuche sowie eine
approximative Suche sind jedoch nur in linearer Zeit zur Textgröße möglich, da hierfür der
gesamte Baum durchwandert werden muss.
3.3 Patricia-Trie
Der 1968 von Donald R. Morrison [Morr68] veröffentlichte Patricia-Trie, ist eine
Abwandlung eines Tries. Das Akronym PATRICIA steht für Practical Algorithm to Retrieve
Information Coded in Alphanumeric. Im Gegensatz zum normalen Trie werden im Patricia-
Trie die Daten in komprimierter Form gespeichert. Dies wird erreicht, indem nur dann ein
Kindknoten erzeugt wird wenn eine Verzweigung im Baum entsteht.
Abbildung 8 Patricia Trie mit dem Text Fischers Fritz fischt frische Fische.
Der Vorteil des Patricia-Trie ist, dass er wesentlich weniger Speicher als der Trie von de la
Briandais benötigt, und die Laufzeit für die Suche einer Zeichenkette mit O(m) gleich bleibt.
30
3.4 Suffix-Trie
Ein Suffix-Trie speichert sämtliche Suffixe eines Wortes in der Baumstruktur. Zum Beispiel
besteht das Wort Fernseher aus den Suffixen Fernseher, ernseher, rnseher, nseher, seher,
eher, her; er und r.
In den Blättern des Suffix-Tries werden die Anfangspositionen der einzelnen Suffixe
gespeichert.
Text F E R N S E H E RPosition 1 2 3 4 5 6 7 8 9
Tabelle 16 Anfangspositionen der Suffixe für den Text Fernseher
31
Abbildung 9 Suffix-Trie für das Wort Fernseher
Der Suffix-Trie eignet sich sehr gut für die Suche nach Teilzeichenketten, jedoch findet er in
der Praxis kaum Verwendung, da er O(n²) Speicherplatz und im ungünstigsten Fall O(n²) Zeit
für seine Erstellung benötigt. [Nels96]
32
3.5 Suffix-Tree
Die Struktur des Suffix-Trees gleicht der des Suffix-Tries, benötigt jedoch wesentlich weniger
Speicherplatz. Dies wird erreicht, indem wie bei dem Patricia-Trie nur dann ein Kindknoten
erzeugt wird, wenn der Baum eine Verzweigung aufweist.
Abbildung 10 Suffix-Tree für den Begriff FERNSEHER
Abbildung 9 zeigt den Suffix-Trie aus Abbildung 10 nachdem er in einen Suffix-Tree
konvertiert wurde. Durch das Löschen der Knoten mit nur einem Nachfolger wurde die
Knotenanzahl von 51 auf 13 reduziert.
Der Suffix-Trie benötigt O(n) Speicherplatz. Weiner [Wein73], McCreight [McCr76] und
Ukkonen [Ukko92b, Ukko95] zeigen, dass der Suffix-Tree in linearer Zeit erstellt werden
kann, wobei der Algorithmus von Ukkonen die häufigste Verwendung findet, da er einfacher
als die beiden anderen Algorithmen zu implementieren ist.
Für viele Anwendungen eignen sich jedoch auch Suffix-Trees nicht, da in der Praxis die
Speicherkomplexität O(n) mit einer Konstante multipliziert werden muss. Eine einfache
Implementierung des Suffix-Trees würde zumindest 20 Bytes pro Indexpunkt benötigen, was
im schlechtesten Fall dem 20-fachen der Textgröße entspricht. Ein Indexpunkt ist ein Zeiger
auf die Suffixposition im Text. Auch die effizientesten Implementierungen [Gieg99]
benötigen noch immer 9 bis 12 Bytes pro Indexpunkt. [BaNa04]
33
3.6 Suffix-Array/PAT-Array
Diese Datenstruktur wurde unabhängig voneinander, von Gonnet [Gonn92], der ihr den
Namen PAT-Array gab und von Manber und Myers [MaMy93], welche sie als Suffix-Array
bezeichneten, entdeckt.
Der Suffix-Array benötigt weniger Speicherplatz als der Suffix-Tree, da er nur die Blätter des
Trees in ein Array speichert. Da die Blätter von links nach rechts durchlaufen und im Array
gespeichert werden, befinden sie sich automatisch in lexikographischer Reihenfolge.
Abbildung 11 Suffix-Array für den Text Fernseher
Die Positionen eines Suffixes im Text werden durch binäres Suchen im Array ermittelt. Da
ein Suffix mehrmals im Text auftreten kann, muss der Anfang sowie das Ende des Bereichs
ermittelt werden in denen die Anfangspositionen für das Suffix gespeichert sind.
Abbildung 12 zeigt den Bereich im Array für die Teilzeichenkette er
Wie in Abbildung 12 zu sehen ist tritt die Teilzeichenkette er im Text Fernseher an den
Positionen 8 und 2 auf.
Der Suffix-Array stellt eine gute Alternative für den Suffix-Tree dar, da er pro Index Punkt
nur noch 4 Bytes benötigt. Wird für jedes Zeichen ein Indexpunkt verwendet, wie es für eine
Teilzeichenkette nötig ist, dann beträgt die Indexgröße die 4-fache Textgröße.
34
3.7 Fazit
Eine fehlertolerante Suchsoftware für Online-Shops soll dem Benutzer möglichst rasch
Ergebnisse liefern. Um dies gewährleisten zu können, ist es nötig, den Index im
Hauptspeicher zu halten, da Zugriffe auf externe Speichermedien verhältnismäßig lange
dauern.
Sofern ausreichend Hauptspeicher verfügbar ist, stellt der Suffix-Array eine mögliche
Alternative dar, da diese Datenstruktur sehr schnelles approximatives Suchen zulässt und im
Gegensatz zu Indizes, welche eine Baumstruktur aufweisen, nur die 4-fache Textgröße
benötigt. Fehlertolerantes Suchen im Suffix-Array kann zum Beispiel durch N-Gramm/Q-
Gramm Suchalgorithmen realisiert werden.
Eine weitere gute Alternative für die zu implementierende Software, stellt der invertierte
Index dar, da er sehr wenig Speicherplatz verbraucht und einfach zu implementieren ist. Für
eine approximative Suche muss zwar das ganze Vokabular durchlaufen werden, dieser
Nachteil wiegt sich jedoch durch den Geschwindigkeitsgewinn eines Suchdurchlaufs im
Hauptspeicher, im Vergleich zu einer Suche auf einen externen Speicher, wieder auf. Zudem
wirkt sich der Nachteil eines vollständigen Durchlaufens der Liste, nur begrenzt auf die
Performance aus, da das Vokabular nur sublinear mit der Textgröße anwächst.
Die restlichen vorgestellten Indizes, sind für die fehlertolerante Suchsoftware nicht geeignet,
da sie mehr Speicherplatz als die beiden erwähnten Alternativen benötigen und/oder keinen
Geschwindigkeitsgewinn gegenüber diesen Alternativen aufweisen.
35
4 Anforderungen an eine fehlertolerante Suchsoftware
Inhalt
Begriffsdefinition Anforderung
Szenarien
Funktionale Anforderungen
Verarbeitung strukturierter Daten
Fehlertolerante Suchfunktion
Exakte Suchfunktion
Verknüpfung von Suchabfragen
Angabe von Wertebereichen
Sortierfunktion
Indexierung
Thesaurus
Mindestähnlichkeit
Protokollierung
Verwendung von Wildcards
Phonetische Suche
Nichtfunktionale Anforderungen
Antwortzeit
Portabilität
Robustheit
In diesem Kapitel werden Anforderungen an eine fehlertolerante Suchsoftware für Online-
Shops spezifiziert. Auf Grundlage dieser Anforderungen wird ein Prototyp für fehlertolerantes
Suchen entwickelt und der fertig gestellte Prototyp auf funktionale Vollständigkeit überprüft.
36
4.1 Begriffsdefinition Anforderung
Der IEEE Standard 610 [IEEE90] definiert eine Anforderung als (1) eine Vorraussetzung oder
Fähigkeit die ein Anwender zur Lösung einer Aufgabe oder zur Erreichung eines Ziels
benötigt. (2) Eine Vorraussetzung oder Fähigkeit, die von einem System oder einer
Systemkomponente erbracht werden muss oder die es/sie besitzen muss, um einen Vertrag,
einen Standard, eine Spezifikation oder andere formell auferlegte Dokumente zu erfüllen. (3)
Eine dokumentierte Darstellung der Vorraussetzungen oder Fähigkeiten wie in Punkt (1) und
(2) beschrieben.
Anforderungen an Softwaresysteme werden oft in funktionale und nichtfunktionale
Anforderungen unterteilt. Funktionale Anforderungen beschreiben, was ein System leisten
soll bzw. über welche Funktionen ein System verfügen soll. Nicht funktionale Anforderungen
beschreiben Eigenschaften wie Zuverlässigkeit, Reaktionszeit, Speicherbedarf, Portierbarkeit
usw. und beziehen sich nicht auf die einzelnen Systemanforderungen, sondern auf das ganze
System. [Somm00]
4.2 Szenarien
Da es einfacher ist einen Bezug zu realen Beispielen herzustellen werden im Folgenden zwei
Szenarien beschrieben, die als Grundlage für die Anforderungsanalyse dienen und einen
groben Überblick geben, was der Prototyp leisten soll.
Ein Benutzer sucht in einem Online-Shop Informationen zu einem Produkt und benutzt dazu
dessen Suchfunktion. Die Suchfunktion des Online-Shops besteht aus einer einfachen Suche
sowie einer erweiterten Suche, die zusätzliche Funktionen wie Festlegen einer Ober- und
Untergrenze des Preises, Auswahl der Größe und Farbe des Produktes, zur Verfügung stellt.
Der Benutzer sucht nach TV-Geräten, jedoch vertippt er sich bei der Eingabe in das
vorgesehene Suchfeld und schreibt Fernsehr anstatt Fernseher. Da er seinen Fehler nicht
bemerkt, drückt er die Eingabetaste um die Suche zu starten. Die Suchsoftware ermittelt jene
Produkte, die den gesuchten Begriff in ihrer Bezeichnung oder Beschreibung beinhalten oder
eine festgelegte Mindestähnlichkeit mit dem Suchbegriff aufweisen. Die Ähnlichkeit wird
durch einen Ähnlichkeitskoeffizient, der mit 1-(k/m) bestimmt ist, berechnet. k steht dabei für
37
die Anzahl der Operation, die nötig sind, um einen Suchbegriff mit der Zeichenlänge m durch
Einfügen, Löschen oder Ersetzen eines Buchstaben, an ein Wort im gesuchten Text
anzupassen. Zudem werden im Suchergebnis auch Treffer angezeigt, die in einem definierten
Zusammenhang mit dem Suchbegriff stehen. Ob ein Zusammenhang mit einem Suchbegriff
besteht, wird in einer Thesaurusdatei festgelegt. Ein Thesaurus ist eine Vokabularsammlung
dessen Begriffe durch Relationen miteinander verbunden sind [Wiki05a]. Diese Relationen
umfassen Synonyme, Ober- und Unterbegriffe. Ein Synonym ist z.B. TV für Fernseher. Als
Beispiel für Ober- und Unterbegriff kann Hose und Jeans angeführt werden, wobei Hose der
Oberbegriff von Jeans ist. Dies hat zur Folge, dass bei einer Suche nach dem Begriff Hose
auch automatisch nach dem Begriff Jeans gesucht wird, umgekehrt gilt dies jedoch nicht. So
könnten im vorliegenden Szenario nicht nur Produkte mit der Bezeichnung Fernseher,
sondern auch automatisch Produkte mit der Bezeichnung TV, TV-Gerät, Plasma TV, LCD-TV
oder Fernsehgerät im Suchergebnis aufscheinen.
Trotz des Rechtschreibfehlers, wird das Suchergebnis innerhalb einer Sekunde angezeigt. Da
nach Empfinden des Benutzers zu viele Treffer gefunden wurden, verwendet er die erweiterte
Suchfunktion. Dort schränkt er den Preis auf 500 bis 700 Euro ein. Ein weiterer Suchvorgang
bringt nun die gewünschten Ergebnisse. Anschließend sortiert der Benutzer das Ergebnis nach
einer beliebigen Eigenschaft wie z. B. Bezeichnung oder Preis. Aus der sortierten
Ergebnisliste wählt er ein Produkt aus um dessen Details zu sehen und verlässt somit den
Funktionsbereich der Suche.
Ein weiteres Szenario bezieht sich auf einen Systementwickler, der mit der Integration der
fehlertoleranten Suchsoftware in ein bestehendes E-Commerce System beauftragt wird. Dazu
installiert der Entwickler zuerst die Software auf ein Testsystem, anschließend legt er die
Datenquelle, welche die Produktinformationen beinhaltet, fest und passt Parameter wie
minimale Höhe des Ähnlichkeitskoeffizienten, zu durchsuchende Produkteigenschaften und zu
indexierende Webseiten des Online-Shops usw. an. Nachdem sämtliche Einstellungen
durchgeführt wurden, testet er die Suche und nimmt gegebenenfalls Änderungen an den
Einstellungen vor. Die Software wird anschließend mit den festgelegten Einstellungen auf das
Produktionssystem übertragen. Durch Mitloggen der Suchanfragen und Auswerten der
Ergebnisse ergänzt ein Wartungsbeauftragter, den Thesaurus der Suchsoftware um fehlende
Einträge. Stellt der Wartungsbeauftragte fest, dass zum Beispiel Suchanfragen mit dem
Begriff TV vorliegen und die Suche keine Treffer lieferte, das Produkt jedoch im Sortiment
38
des Onlineshops unter der Bezeichnung Fernseher geführt wird, so ergänzt er den Thesaurus
um das Synonym TV für Fernsehgerät.
4.3 Funktionale Anforderungen
4.3.1 Verarbeitung strukturierter Daten
Produktdaten müssen in einer beliebigen eindimensionalen Struktur gespeichert werden
können. Die gesamten Daten zu einem Produkt könnten zum Beispiel in Bezeichnung,
Beschreibung und Preis aufgeteilt werden. Die einzelnen Teilbereiche der Produktdaten
werden im Folgenden als Felder bezeichnet. Eine Suche muss nach einem oder mehreren
Feldern möglich sein. Auf ein Feld kann sowohl durch einen eindeutigen Feldnamen wie z.B.
Preis als auch durch die Nummer des Feldes angesprochen werden. Die Nummerierung der
Felder beginnt bei 0.
4.3.2 Fehlertolerante Suchfunktion
Die fehlertolerante Suchsoftware soll sowohl nach Produkten als auch nach Webseiten (z.B.:
AGBs) des Online-Shops suchen. Die Analyse und Bereitstellung der Webseiteninhalte
erfolgt durch einen Webcrawler und gehört nicht zum Funktionsumfang der Software.
Fehlerhafte Suchbegriffe, die durch Vertippen oder Rechtschreibfehler entstehen, müssen von
der Software so verarbeitet werden, dass trotz des Fehlers nach dem korrekten Produkt oder
der richtigen Webseite gesucht wird. Dies gilt jedoch nur, sofern der Suchbegriff einen
Ähnlichkeitskoeffizienten aufweist, der größer oder gleich einem vom Systementwickler
festgelegten Wert ist. Werden mehrere Suchbegriffe eingegeben, so darf die Suchsoftware nur
jene Treffer als Ergebnis ausgeben, die alle gesuchten Begriffe beinhalten. Zahlen im
Suchbegriff müssen auch von der fehlertoleranten Suchfunktion exakt gesucht werden. Eine
Abfrage nach Canon i 950 darf daher im Ergebnis keine Treffer mit Canon i 990 beinhalten.
Zwischen Groß- und Kleinschreibung soll nicht unterschieden werden, sie darf daher für das
Ergebnis der Suchabfrage keine Rolle spielen.
39
4.3.3 Exakte Suchfunktion
Die Suchsoftware muss neben der fehlertoleranten Suchfunktion auch eine exakte
Suchfunktion bereitstellen. Dies ist insofern nötig, da z.B. ein Auswahlmenü auf der
Suchseite des Online-Shops festgelegte Werte wie grau, blau usw. enthalten kann. Wählt der
Benutzer nun den Wert blau aus, und ist vom Systementwickler ein Ähnlichkeitskoeffizient <
0,5 gesetzt, so wäre es möglich, dass im Suchergebnis auch Treffer mit dem Wert grau
aufscheinen. Treffer der exakten Suchfunktion weisen einen Ähnlichkeitskoeffizienten von 1
auf und stimmen vollständig mit dem Suchbegriff überein. Ob eine komplette
Übereinstimmung des Suchbegriffs innerhalb einer Teilzeichenkette zu einem Treffer führen
soll, muss beim Aufruf der Suchfunktion angegeben werden können.
4.3.4 Verknüpfung von Suchabfragen
Suchabfragen können miteinander durch eine UND, ODER sowie einer UND NICHT
Operation verknüpft werden. Durch eine UND Verknüpfung wird ein Suchergebnis erstellt,
welches nur jene Treffer enthält, die in beiden Ergebnissen vorkommen. Eine ODER
Verknüpfung erzeugt ein Suchergebnis, dass die Treffer zweier Sucherabfragen, beinhaltet.
Dabei dürfen Treffer die von beiden Abfragen gefunden werden, nur einmal im Suchergebnis
aufscheinen. Eine UND NICHT Operation erstellt ein Suchergebnis, welches die Treffer der
ersten Suchabfrage abzüglich der Treffer der zweiten Suchabfrage beinhaltet.
4.3.5 Angabe von Wertebereichen
Die Suchsoftware muss eine Funktion zur Verfügung stellen, die es ermöglicht, eine
Wertebereichsabfrage auf ein Feld durchzuführen. Der Wertebereich wird durch eine Ober-
und Untergrenze definiert, die jeweils durch Angabe einer Zahl oder durch einen Null Wert
festgelegt werden. Ein Null Wert wird als ∞ interpretiert und darf jeweils nur für eine der
beiden Grenzen gesetzt werden. Treffer des Suchergebnisses sind größer oder gleich der
Untergrenze und kleiner oder gleich der Obergrenze, dabei wird mindestens bis zu den ersten
4 Kommastellen verglichen. Eine Wertebereichsabfrage muss auf ein Feld erfolgen, welches
ausschließlich Zahlen beinhalten (z.B. Abfrage auf ein Feld mit Produktpreisen). Ist dies nicht
der Fall so wird ein Suchergebnis ohne Treffer zurückgeliefert.
40
4.3.6 Sortierfunktion
Das Suchergebnis muss nach einzelnen Feldern sowie nach dem Ähnlichkeitskoeffizienten
sortiert werden können. Neben dem zu durchsuchenden Feld ist die Angabe eines Parameters
möglich, der festlegt ob das Suchergebnis auf- oder abwärts sortiert wird. Bei einer
Aufwärtssortierung haben Zahlen Vorrang vor Buchstaben. Eine Aufwärtssortierung reiht die
Treffer des Suchergebnisses zuerst nach Sonderzeichen, dann nach Ziffern von 0 bis 9 und
anschließend nach Buchstaben von A bis Z. Bei einer Abwärtssortierung werden die Treffer
des Suchergebnisses umgekehrt von Z bis A, dann von 9 bis 0 und anschließend nach
Sonderzeichen gereiht. Die Sortierreihenfolge der Sonderzeichen selbst wird hier nicht
festgelegt. Wird der Sortierfunktion kein Wert für die Sortierrichtung mitgegeben so erfolgt
eine standardmäßige Aufwärtssortierung.
4.3.7 Indexierung
Ein Index ist eine Datenstruktur zum schnellen Auffinden von Datensätzen. Der Index muss
heterogene Datenstrukturen verwalten können, damit eine Suchabfrage sowohl nach
Webseiten als auch nach Produkten des Onlineshops möglich ist. Der Index darf die 3fache
Größe gegenüber der ursprünglichen Datenmenge nicht überschreiten und muss im
Hauptspeicher gehalten werden können. Der Größenvergleich bezieht sich auf
unkomprimierte Produktdaten in einem CSV(Comma Separated Value) Dateiformat und der
Größe des erstellten Index.
4.3.8 Thesaurus
Durch die Angabe einer Thesaurusdatei wird bei einer Suchabfrage automatisch nach
Synonymen und Unterbegriffen des Suchbegriffes gesucht. Die Thesaurusdatei steht als XML
Datei zur Verfügung. Die Struktur der XML Datei ist durch folgende DTD (Document Type
JUnit ist ein Testframework für Komponententests. Eine Komponente ist ein Baustein zur
Softwareherstellung, welche ihre Funktionalität über Schnittstellen anbietet [Szyp98]. Der
Quellecode für das Testframework ist frei verfügbar und steht unter IBM’s Common Public
Lizenz Version 1.0. Diese Lizenz erlaubt es JUnit für die Entwicklung kommerzieller
Produkte einzusetzen.
Komponententests oder auch Unit Tests, wie sie im Englischen genannt werden, prüfen das
Verhalten der Bausteine. Es wird geprüft, ob ein bestimmter Eingabewert einer Methode
einen erwarteten Rückgabewert erzeugt. [Mass04]
Anhand eines sehr einfachen Beispiels wird nun gezeigt wie Tests in JUnit implementiert
werden.
public class Calculator {
public double add(double number1, double number2) {
return number1 + number2;
}
}
Codebeispiel 1 Die Klasse Calculator berechnet die Summe zweier Zahlen.Übernommen aus JUnit in Action [Mass04]
Die Klasse Calculator stellt eine Methode add zur Verfügung, welche die Summe zweier Zahlen berechnet. Um sicher zu gehen, dass die Methode die Summe richtig berechnet, wird sie mittels der Klasse TestCalculator getestet.
import junit.framework.TestCase;
public class TestCalculator extends TestCase{
public void testAdd() {
Calculator calculator = new Calculator();
double result = calculator.add(10, 50);
assertEquals(60, result, 0);
}
}
Codebeispiel 2 Die Klasse TestCalculator prüft ob die Methode add der Klasse Calculator den erwarteten Wert erzeugt. Übernommen aus JUnit in Action [Mass04]
56
Die Klasse TestCalculator erweitert die Klasse TestCase und prüft mittels der Methode
testAdd() die Methode add() der Klasse Calculator. Der erste Wert der Methode assertEquals
steht für das erwartete Ergebnis, der zweite Wert steht für das tatsächliche Ergebnis. Der
dritte Parameter gibt eine maximale Abweichung der beiden ersten Parameter an. Er kann
meist vernachlässigt werden, da er nur in speziellen Fällen für Fließkommaberechnungen
benötigt wird. Neben der Methode assertEquals gibt es noch eine Reihe weiterer Methoden,
wie assertTrue, assertNotNull usw., zur Überprüfung der Bausteine.
Klassen, welche die Klasse TestCase erweitern können zu einer TestSuite zusammengefügt
werden. Die Verwendung einer TestSuite eignet sich um zusammengehörige Tests zu
gruppieren.
Mittels eines Build Werkzeuges wie Ant oder Maven können Komponententests automatisiert
werden. Durch eine entsprechende Konfiguration der Build Datei, werden bei jedem Build
Prozess sämtliche Komponententests durchgeführt. Somit kann sichergestellt werden, dass
alle getesteten Komponenten im Laufe des gesamten Entwicklungsprozess funktionieren.
Sollte ein Test fehlschlagen, da eine getestete Komponente verändert wurde und somit nicht
mehr das erwartete Ergebnis liefert, dann bricht das Build Werkzeug den
Veröffentlichungsprozess ab und teilt dem Benutzer mit, welcher Test nicht erfolgreich
durchgeführt werden konnte.
6.2.2 Ant
Ant ist ein auf Java basierendes Build Werkzeug. Mit diesem Werkzeug lassen sich Aufgaben
wie das Kompilieren von Code, Erstellen von Dokumentationen, das Durchführen von Tests
und weitere Routineaufgaben automatisieren. Dies ist insbesondere bei größeren Projekten
von Vorteil, da mit nur einem Knopfdruck eine aktuelle Version des Programms erstellt
werden kann. Konfiguriert wird Ant über eine XML Datei die üblicherweise unter dem
Namen build.xml gespeichert wird.
57
Abbildung 19 Konzeptionelle Darstellung einer Build Datei. Übernommen aus [HaLo03]
Abbildung 19 stellt einen Build Prozess konzeptionell dar. Der Prozess setzt sich aus
verschiedenen Aufgaben (Tasks) zusammen, die zu Zielen (Targets) gruppiert wurden.
Zwischen Zielen kann es Abhängigkeiten geben. So muss zuerst das Ziel init erfolgreich
durchgeführt werden, bevor die Ziele compile und doc abgearbeitet werden können. Die
Aufgaben des Zieles deploy können erst erledigt werden, wenn die Aufgaben aller anderen
Ziele durchgeführt wurden.
Das folgende Codebeispiel zeigt die Umsetzung der konzeptionellen Darstellung in Form
Abbildung 22 Architektur der Suchsoftware............................................................................63
Abbildung 23 architektureller Überblick der Indexkomponente..............................................64
Abbildung 24 architektureller Überblick der Suchkomponente...............................................65
Abbildung 25 zeigt Struktur und Aufbau des Thesaurus..........................................................67
Abbildung 26 Auszug der Textdatei.........................................................................................73
Abbildung 27 zeigt eine Ergebnisseite der Beispielapplikation...............................................76
Abbildung 28 Einfache Suche nach dem Begriff Hose............................................................78
Abbildung 29 Einfache Suche nach dem Begriff Microsoft Keyboard....................................78
Abbildung 30 Erweiterte Suche nach dem Begriff Hose..........................................................79
Abbildung 31 Suche nach dem Begriff Hose mit zusätzlicher phonetischer Suche.................79
84
Literaturverzeichnis
[Answ05] Answers.com, Heaps’ law, http://www.answers.com/topic/heaps-law, Abruf am 2005-04-05.
[Ant05] Apache Ant, http://ant.apache.org, Abruf am 2005-05-11
[Apac05] Apache Software License, Version 2.0, Jänner 2004, Abruf am 2005-04-06
[BaNa04] Baeza-Yates, Ricardo A.; Navarro, Gonzalo: Text Searching: Theory and Practice, Formal Languages and Applications, Springer, Seite 565-597, 2004
[BaNe99] Baeza-Yates, Ricardo A.; Ribeiro-Neto, Berthier: Modern Information Retrieval. ACM Press / Addison-Wesley, 1999
[BaYa92] Baeza-Yates, Ricardo; Gonnet Gaston H.: A new approach to text searching. Communications of the ACM 35(10), S. 74-82, 1992
[BaYa91] Baeza-Yates, Ricardo.: Some new results on approximate string matching. In Workshop on Data Structures, 1991
[Brian59] de la Briandais, Renee: File Searching Using Variable Length Keys. Proceedings of the Western Joint Computer Conference, 1959
[Cutt00] Cutting, Doug: The Lucene Search Engine, Inktomi Seminar, 16 Juni 2000, http://lucene.sourceforge.net/talks/inktomi, Abruf am 2005-04-07
[Egot05] Egothor, http://www.egothor.org, Abruf am 2005-04-06
[Fred60] Fredkin, Edward: Trie Memory, Communications of the ACM, 3(9), Seite 490-499, 1960
[Gadd90] Gadd, T.N.: PHONIX: The Algorithm, 24(4), S. 363, 1990
[Gadd88] Gadd, T. N.: “Fisching fore werds”: phonetic retrieval of written text in information systems. 22(3), S. 222, 1988
[GaHe95] Gamma Erich, Helm Richard, Johnson Ralph, Vlissides John: Design Patterns, Elements of Reusable Object-Oriented Software, Addison Wesley, 1995
[Gieg99] Giegerich, Robert; Kurtz, Stefan; Stoye, Jens: Efficient implementation of lazy suffix trees. In Proc. 3rd Workshop on Algorithm Engineering, Lecture Notes In Computer Science 1668, Seite 30-42, 1999
[GNU05] GNU Lesser General Public License, http://www.gnu.org/copyleft/lesser.html, Abruf
[Gülc04] Gülcü, Ceki: The Complete log4j Manual, 2004
[HaLo03] Hatcher, Erik; Loughran, Steve: Java Development with Ant, Manning Publications,
2003
[Heap78] Heaps, H. S.: Information Retrieval, Computational and Theoretical Aspects. Academic Press, 1978
[HoUl] Hopcroft, John E.; Ullman, Jeffrey D.: Introduction to Automata Theory, Languages and Computation, Addison-Wesley, 1979
[IBM05] IBM, Struts, an open-source MVC implementation,
http://www-106.ibm.com/developerworks/library/j-struts/?dwzone=java, Abruf am
2005-05-16
[IEEE90] Industry of Electrical and Electronics Engineers: IEEE Standard Glossary of
Software Engineering Terminology. IEEE Std.610.12-1990, The Institute of Electrical
and Electronic Engineers, New York, 1990.
[JMet05] Apache JMeter, http://jakarta.apache.org/jmeter, Abruf am 2005-05-17
[Juni05] JUnit, http://junit.sourceforge.net, Abruf am 2005-05-11
[Knut73] Knuth, Donald: The Art of Computer Programming 3: Sorting and Searching, Addison-Wesley-Verlag, 1973
[LaWa75] Lowrance, R.; Wagner, Robert A.: An Extension of the String-to-String Correction Problem. Journal of the ACM 22(2), S. 177-183, 1975
[Lawr90] Lawrence, Philips: “Hanging on the metaphone”. Computer Language Magazine 7(12), S. 38-44, Dezember 1990
[Lawr00] Lawrence, Philips: The Double-Metaphone Search Algorithm, C/C++ User’s Journal 18(6), Juni 2000
[Leve65] Levenshtein, Vladimir I.: Binary Codes capable of correcting spurious insertions and deletions of ones. Problems of Information Transmission 1(1), S. 8-17, 1965
[Leve66] Levenshtein, Vladimir. I.: Binary Codes capable of correcting deletions, insertions and reversals. Soviet Physics Doklady 10(8), S. 707-710, 1966
[Log05] Apache Log4J, http://logging.apache.org, Abruf am 2005-05-11
[Luce05] Apache Lucene, http://lucene.apache.org, Abruf am 2005-04-06
[MaMy93] Manber, Udi; Myers, Eugene W.: Suffix arrays: a new method for on-line string searches. SIAM Journal on Computing, 22(5), Seite 935-948, 1993
[Mave05] Apache Maven, http://maven.apache.org, Abruf am 2005-05-11
[McCr76] McCreight, Edward M.: A Space-Economical Suffix Tree Construction Algorithm, Journal of the ACM, 23(2), Seite 262-272, 1976
[Morr68] Morrison, Donald R.: PATRICIA – Practical Algorithm To Retrieve Information Coded in Alphanumeric, Journal of the ACM, 15(4), Seite 514-534, 1968
[Myers86] Myers, Eugene W.: Incremental alignment algorithms and their applications. Tech. Rep. TR86-22, Dept. of Computer Science, Univ. of Arizona, 1986
[NARA00] US National Archives and Records Administration: The Soundex Indexing System. http://www.archives.gov/research_room/genealogy/census/soundex.html, 2000-02-19, Abruf am 2004-11-05.
[Nava01] Navarro, Gonzalo: A Guided Tour to Approximate String Matching. ACM Computing Surveys 33(1), S. 31-88, 2001
[Nels96] Nelson, Mark: Fast String Searching With Suffix Trees, Dr. Dobb’s Journal, http://www.dogma.net/markn/articles/suffixt/suffixt.htm, 1996, Abruf am 2005-03-27.
[PfPo96] Pfeifer, Ulrich; Poersch, Thomas; Fuhr, Norbert: Retrieval Effectiveness of Proper Name Search Methods. Information Processing and Management, 1996
[Phon05] Phonetix, tangentum technologies,
http://www.tangentum.biz/en/products/phonetix/index.html, Abruf am 2005-04-25
[RiAv04] Richardson, Clay W.; Avondolio, Donald; Vitale, Joe; Len, Peter; Smith, Kevin T.: Professional Portal Development with Open Source Tools: JavaTM Portlet API, Lucene, James, Slide. Wrox, 2004
[Ukko92a] Ukkonen, Esko: Approximate string-matching with g-grams and maximal matches. Theoretical Computer Science, 92, S. 191-211, 1992
[Ukko92b] Ukkonen, Esko: Constructing Suffix-trees On-Line in Linear Time. Algorithms, Software, Architecutre: Information Processing, 1(92), Seite 484-492
[Ukko95] Ukkonen, Esko: On-line Construction of Suffix Trees. Algorithmica, 14(3), Seite 249-260, 1995
[Ukko85] Ukkonen, Esko: Finding approximate patterns in strings. Journal of Algorithms6(1-3), S. 132-137, 1985
[Wein73] Weiner, P.: Linear pattern matching algorithms. In Proceedings of IEEE Symposium on Switching and Automata Theory, Seite 1-11, 1973
[Wiki05a] Wikipedia - Die freie Enzyklopädie, http://de.wikipedia.org/wiki/Thesaurus, Abruf am