Ausarbeitung zum Seminar „Active Data Managment“ an der Freien Universität Berlin, Fachbereich Mathematik und Informatik Sommersemester 2001 THEMA: Prädikat-Matching Algorithmen in Benachrichtigungssystemen Betreuung: Prof. Dr. H. Schweppe Annika Hinze Torsten Schlieder vorgelegt von: Sven Bittner A. Einführung Benachrichtigungssysteme basieren auf folgender Idee: Auf der einen Seite stehen die Anbieter. Sie verfügen über eine große Anzahl von Informationen, die einem breiten Publikum zugänglich gemacht werden sollen. Dazu schicken die Anbieter ihre Informationen an verschiedene Kanäle, welche durch Themengebiete gekennzeichnet sind. Die Abonnenten auf der anderen Seite, können sich bei einem oder mehreren dieser Kanäle anmelden. Sie erhalten dann alle Informationen, die über diesen Kanal eintreffen. Eine Erweiterung dieses klassischen Ansatzes sind inhaltsbasierte Benachrichtigungssysteme. Die Abonnenten können hier Einfluss nehmen, welche Artikel an sie weitergeleitet werden. Eine einfache Art der Einflussnahme ist durch Angabe von Stichworten möglich. Die eintreffenden Informationen werden auf diese getestet und nur bei Übereinstimmung weitergeleitet. Als besserer Ansatz ist der folgende vorstellbar: Zur Beschreibung der Art und des Inhalts werden die Artikel von den Anbietern durch verschiedene Attribute gekennzeichnet. Ein Abonnent kann nun anhand seiner Interessen, für ihn in Frage kommende Attribute bestimmen und so festlegen, welche Informationen an ihn weitergeleitet werden sollen. Diese Inhaltsbestimmung nennt man auch Profil. Vorteil eines solchen Systems ist es, dass sowohl die Anbieter den Inhalt ihrer Informationen genau spezifizieren können, als auch die Abonnenten in der Lage sind, ihre Interessen genau anzugeben. Eine Stichwortsuche auf den Artikeln ist nicht mehr notwendig. Damit entfallen auch die dadurch entstehenden Fehler, da bekanntlich das Vorhandensein oder die Abwesenheit von Schlüsselwörtern nicht auf einen Inhalt der Artikel schließen lassen. Somit wird die Qualität des Filterns von relevanten Artikeln extrem erhöht, vorausgesetzt die Attribute entsprechen auch den Tatsachen. Ebenfalls ist es möglich Nicht-TextArtikel an interessierte Abonnenten zu verteilen. Bei der Umsetzung dieses Ansatzes kommt es grundlegend darauf an, wie schnell es möglich ist, einen eintreffenden Artikel, im folgenden auch Event/Ereignis genannt, an alle interessierten Abonnenten weiterzureichen. Charakteristisch für ein solches Benachrichtigungssystem sind eine große Zahl von Abonnenten und viele zu unbekannten Zeitpunkten eintreffende Events. Im folgenden werden verschiedene Ideen zur Implementierung solcher Systeme betrachtet. Zuerst wird ein allgemeiner Algorithmus analysiert. Danach die Ansätze der Arbeiten „Matching Events in a Content-based Subscription System“ [1] und „Efficient Recognition of Events in a Distributed System“ [2] aufgezeigt und verglichen. Schließlich folgt in Abschnitten E ff eine Einordnung der genannten Ideen, Kritikpunkte und die Betrachtung weitergehender Fragestellungen, welche in beiden Arbeiten offen bleiben. B. Naive Lösung/einfacher Algorithmus Bei einer ersten Betrachtung des Problems des Zuordnen der Artikel zu den Abonnenten gelangt man zu folgender Lösung: Teste für alle Abonnenten, ob ein eintreffendes Ereignis relevant ist. Als Vorteil dieser Lösung ist die einfache Implementierung zu sehen. Man geht die gesamte Abonnentenmenge durch und testet, ob die Attribute den spezifizierten Anforderungen genügen. Nachteilig hingegen stellt sich die Laufzeit dar. Bei einer Gesamtzahl von n Abonnenten und einer Testzeit von f für ein Ereignis, liegt die Laufzeit bei O(n*f). Angesichts der großen Zahl zu erwartender Abonnenten und in hohen Frequenzen eintreffender Artikel wären andere Algorithmen, deren Laufzeiten nicht im linearen Verhältnis zur Abonnentenzahl liegen, als besser geeignet anzusehen. Zwei solche Ideen werden im folgenden betrachtet. Einer der Hauptunterschiede ist, dass nicht mehr die einzelnen Abonnenten überprüfen, ob ein Ereignis relevant ist, sondern die Ereignisse sich die passenden Abonnenten suchen. C. Lösung durch Aufbau eines Matching Tree Im folgenden wird eine Zusammenfassung des Artikels „Matching Events in a Content-based Subscription System“ [1] gegeben. Eine Wertung des Ansatzes folgt im späteren Verlauf in den Abschnitten E ff. 1. Problemverfeinerung/weitere Annahmen Zur Nutzung der vorgestellten Ideen in einem Benachrichtigungssystem sind einige besondere Annahmen zur Einschränkung des Problembereichs zu machen. Ein jeder Abonnent sub wird als Konjunktion von Prädikaten angesehen. Dabei soll jedes Prädikat einen einfachen Test auf genau einem Attribut eines Events darstellen. Solch ein einfacher Test kann z.B. auf Gleichheit, Ungleichheit oder Enthaltensein in einem Bereich überprüfen. Ein jedes Prädikat liefert einen booleschen Wert, welcher dem Zutreffen des Test entspricht. Durch Konjunktion dieser einzelnen Werte erhält man dann ein Gesamtergebnis. Dieses steht entweder für Interesse oder Nichtinteresse des Abonnenten am getesteten Event. Eine formale Definition eines Abonnenten könnte so aussehen: sub := pr1 AND pr2 AND ... AND prk pri := testi( event ) resi (der Test testi soll als Ergebnis resi liefern) Suchen wir z.B. Personen, welche durch Wohnort und Geburtstag gekennzeichnet sind, wären folgende Prädikate denkbar: pr1 = test1( event ) „Berlin“ pr2 = test2( event ) „<“ test1 = werte Attribut Wohnort aus test2 = vergleiche Attribut Geburtstag mit dem Datum 01.01.1979 Weiterhin wird eine vorgegebene Reihenfolge der möglichen Attribute vorausgesetzt. Nicht alle Attribute müssen von den Abonnenten spezifiziert werden, da ihnen die Möglichkeit gelassen werden soll, vom Wert eines oder mehrerer Attribute unabhängig zu sein. Dieser Fall wird als don’t care bezeichnet. Der vorgeschlagene Algorithmus zerlegt die Lösung des Problems in zwei Phasen. In der ersten wird eine interne Datenstruktur, der Matching Tree, aufgebaut und in der anderen, die Auswertung der eintreffenden Events auf Grundlage dieses Matching Tree durchgeführt. 2. Aufbau/Abarbeitung des Matching Tree Der Matching Tree stellt in seiner Struktur einen Baum dar. Die Blätter des Baumes enthalten die Abonnenten (Subscribers). Ein jeder innerer Knoten stellt einen Test dar. Die Kanten sind als Ergebnisse dieser Tests zu sehen. Ein don’t care Fall wird durch eine *-Kante symbolisiert. Testet man beispielsweise das Attribut auf Gleichheit (test1 im obigen Beispiel), so stellen die Kanten die Vergleichswerte dar. Ein Beispiel eines Baumes mit Gleichheitstests ist in Bild1 zu sehen (die eingezeichneten Pfeile sind erst einmal zu ignorieren). a) Algorithmus zum Baumaufbau In den Matching Tree werden alle Abonnenten mit ihren Prädikaten eingetragen. Dazu werden diese und deren Prädikate nacheinander betrachtet. Dabei wird der Baum durchlaufen und bei Bedarf ergänzt. Jeder Abonnent startet seine Betrachtungen in der Baumwurzel. Entweder ist der Test im betrachteten Knoten mit dem Attributtest des aktuellen Abonnenten identisch. Dann wird eine Kante mit dem Ergebnis des Abonnenten gesucht. Ist sie vorhanden, wird ihr gefolgt. Sonst wird eine derartige Kante erzeugt (sie zeigt auf einen neuen leeren Knoten) und dieser gefolgt. Danach bearbeitet man das nächste Attribut. Schwieriger wird es, wenn der Knotentest und der aktuelle Abonnententest nicht übereinstimmen. Hat der Knoten keine *-Kante, so fügt man eine solche dazu und trägt den Abonnententest in deren Folgeknoten ein. Danach wird das nächste Attribut bearbeitet. Ist schon eine *-Kante vorhanden, so folgt man dieser und versucht, den Test im nächsten Knoten einzutragen. Sind alle Prädikate in den Baum übertragen, wird der Abonnent dem Knoten hinzugefügt (der Knoten ist dann entweder leer oder er ist schon ein Blatt mit Abonnenten). b) Algorithmus zum Finden der relevanten Abonnenten Das Finden der Abonnenten besteht in einer Abarbeitung der erzeugten Baumstruktur. Dabei kann sowohl Tiefen- als auch Breitensuche verwendet werden. Für einen Event gestaltet sich dies folgendermaßen (es wird Tiefensuche durchgeführt). Beginne in der Wurzel. Führe den Test des aktuellen Knotens auf dem Event aus. Folge der Kante mit dem richtigen Testergebnis und arbeite den nächsten Knoten ab. Gibt es eine don’t care Kante, so folge auch dieser. Die erreichten Blätter stellen die am Artikel interessierten Abonnenten dar. Erreicht man keine Blätter, so gibt es keine relevanten Abonnenten. Der folgende Pseudocode soll diese Idee noch einmal verdeutlichen. procedure match( tree, event ) visit( tree, root, event ) procedure visit( tree, v, event ) IF v ist Blatt THEN Abonnenten in v sind relevant ELSE führe den Test in v auf event aus IF v hat Kante e mit Testergebnis THEN visit( tree, Zielknoten von e, event ) IF v hat *-Kante e THEN visit( tree, Zielknoten von e, event ) 3. Analyse der Algorithmen Im folgenden werden Speicher- und Zeitbedarf der beiden Algorithmen aufgezeigt. Dabei wird die Analyse auf den Fall beschränkt, dass alle Tests die Gleichheit eines Attributes überprüfen. Im genannten Spezialfall erhält man immer einen Baum der Höhe k, wobei k, hier wie im folgenden, die Zahl der Attribute/Prädikate darstellen soll. Das beruht auf der Tatsache, dass jeder Abonnent beim Eintragen in den Baum entweder eine passende Kante findet, oder die benötigte zum Knoten hinzufügt. Ein Übergehen eines Knotens, wegen einer anderen Art des Tests, bleibt aus. In jeder Ebene i des Baumes befinden sich Knoten, welche genau das i. Attribut eines Events testen. Die ausgehenden Kanten sind mögliche Werte des Attributes. a) Zeitverhalten für den Baumaufbau Um einen Abonnenten in den Baum einzutragen, müssen alle seine Attribute abgearbeitet werden. Dabei ist entweder Kanten zu folgen oder eine Kante und ein neuer Knoten in den Baum einzutragen. Bei k Attributen ergibt sich ein Aufwand von O(k+1), wenn man die Zahl Knotenbesuche als ausschlaggebende Operation ansieht. Sind insgesamt n Abonnenten vorhanden, ergibt sich eine Gesamtlaufzeit von O(n*k). b) Speicherplatz für den Baum Für jeden der n Abonnenten werden im schlimmsten Fall k+1 Knoten zum Baum hinzugefügt. k Knoten enthalten dabei einen Test und einer stellt ein Blatt, mit dem Abonnenten als Inhalt, dar. Zusätzlich wird der Baum um maximal k Kanten erweitert. Also ergibt sich ein Speicheraufwand von O(n*k). Somit ist sowohl bei Aufbauzeit als auch bei Speicher für den Baum Linearität zur Anzahl der Abonnenten gegeben. c) Zeitverhalten zum Finden der relevanten Abonnenten Als Zeitmaß soll wieder die Anzahl der besuchten Knoten angenommen werden. Die Auswertung des Gleichheitstests und das Finden des Folgeknotens ist in konstanter Zeit möglich und das Folgen der Kanten ebenfalls. Praktisch umsetzbar wäre das z.B. mit Hashtabellen, welche die Werte der Attribute als Schlüssel und die Kanten des Baumes als Einträge enthalten. Eintragen und Suchen in Hashtabellen ist durchschnittlich in konstanter Zeit möglich [3]. Die Zahl der besuchten Knoten ist von mehreren Faktoren abhängig. Je mehr Attribute vorhanden sind, desto höher ist der Baum und somit auch der Weg zu einem möglichen Blatt. Haben viele Abonnenten don’t care Tests, müssen häufig zwei Pfade verfolgt werden. Auch der Event selbst ist für den zu wählenden Pfad entscheidend, also für die Zahl der Knotenbesuche. Eine einfache obere Schranke der Knotenbesuche ergibt sich wie folgt. Man stelle sich einen Baum vor, dessen Knoten jeweils genau zwei Kanten enthalten. Zum einen eine don’t care Kante und zum anderen eine Kante mit dem beliebigen Wert v. Um einen Event zu testen, dessen Attribute alle aus dem Wert v bestehen, müssen nun sämtliche Knoten des Baumes besucht werden. Die Anzahl der Knoten liegt zwischen n und k*n, wenn n Abonnenten in den Baum eingetragen sind. Somit ist die Suchzeit im schlimmsten Fall proportional zur Anzahl der Abonnenten und Attribute. Eine andere obere Schranke ist wie folgt zu erhalten. In jeder Ebene des Baumes verfolgt man maximal 2 Kanten (einer mit einem Wert und einer don’t care Kante). Also werden insgesamt maximal 2^0 + 2^1 +2^2 + ... + 2^k = 2^(k+1)-1 Knoten besucht. Diese Zahl ist zwar unabhängig von der Abonnentenzahl, jedoch exponentiell in der Anzahl der Attribute. Ein ebenfalls unbefriedigendes Resultat. Im besten Fall enthält der Baum oder der zu nehmende Weg keine don’t care Kanten. Dann wird pro Ebene genau einer Kante gefolgt. Insgesamt werden k Knoten besucht, die Abarbeitung ist also in konstanter Zeit möglich (es gibt eine feste Zahl von Attributen). Aufgrund dieser Ergebnisse analysieren die Autoren nun die zu erwartende Zeit zum Finden der Abonnenten für einen zufälligen Event in einem zufälligen Baum. Dabei erhalten sie eine Laufzeit, welche sublinear von der Zahl der Abonnenten abhängt. Die Größe des zu erwartenden Exponenten ist dabei von Art und Anzahl der Attribute des Systems anhängig. In einigen Fällen liegt er bei 0,5. Der Beweis ist in der Originalarbeit in Abschnitt 4 nachzulesen. 4. Optimierungen Durch Änderungen beim Aufbau des Baumes kann eine Verbesserung der Laufzeit des Suchalgorithmus erreicht werden. Da die Minimierung dieser Zeit die Effektivität des Algorithmus widerspiegelt, kann eine Vergrößerung des Speicherbedarfs als kalkulierbar hingenommen werden. Eine Möglichkeit der Optimierung gestaltet sich wie folgt. Enthält ein Knoten v des Baumes nur eine don’t care Kante (v,w), so kann dessen Elternknoten direkt auf w zeigen. Knoten v kann aus dem Baum entfernt werden. In Bild1 könnte also Knoten A direkt durch Knoten B ersetzt werden (zweifache Anwendung der Regel). Praktische Tests ergaben bei dieser Art der Optimierung Verbesserungen der Suchzeit um bis zu 60%. Eine weitere Optimierung kann durch Minimierung der Zahl der Auswertungen ein und desselben Attributes erzielt werden. Es wird versucht zu verhindern, dass mehrere Pfade im Baum aufgrund von don’t care Kanten besucht werden. *-Kanten wird nun per Definition nur bei Knoten ohne andere Kanten gefolgt. Nach dem Baumaufbau werden in jedem Knoten zusätzlich Kanten zu den Knoten gespeichert, welche durch Ersetzen von Attributen im bisherigen Weg durch einen don’t care Fall, erreichbar sind. Bild1. Matching Tree Beim Auswerten werden alle diese Folgeknoten betrachtet und als mögliche Wege bearbeitet. Das Folgen von *-Kanten ist somit hinfällig, außer ein Knoten enthält nur diese eine Kante, was bei der ersten Optimierung auch entfällt. In Bild1 werden in Knoten C (Weg 123) die Knoten D (Weg ***), E (Weg **3), F (Weg *2*), G (Weg 1*3), H (Weg 12*) und K (Weg 1**) als Folgeknoten gespeichert. Nicht hingegen Knoten A (Weg 1*1), da das 3. Attribut nicht mit dem 3. Attribut von Knoten C übereinstimmt. Die Werte aller dieser Folgeknoten werden nun beim Auswerten von C betrachtet. Jedoch erhöht sich bei dieser Optimierung der notwendige Speicherplatz. Praktisch ergaben sich dadurch Verbesserungen von bis zu 20%. Das Erzeugen von mehreren Bäumen kann ebenfalls zur Effizienzsteigerung genutzt werden. Attribute, welche von kaum einem Abonnenten als don’t care gekennzeichnet sind, werden als Einstieg in die verschiedenen Bäume genutzt. Eine Anwendung ist sogar auf mehreren Ebenen vorstellbar. Diese Bäume enthalten dann keine Test für diese speziellen Indexattribute. Allerdings ist zu beachten, dass Abonnenten, welche doch don’t care Fälle eines Indexattributes enthalten, in mehrere der Bäume eingetragen werden müssen. Insgesamt gibt es V^m solche Doppeleintragungen, wenn es V Werte pro Attribut gibt und don’t care Fälle bei m Indexattributen eines Abonnenten auftreten. Deshalb muss eine Abwägung zwischen zusätzlichen Speicherbedarf und Zeitgewinn getroffenen werden. Auch möglich wäre es, die Attribute so zu ordnen, dass die Anzahl ihrer möglichen Werte von der Baumwurzel her zunimmt. Dadurch sind bei Knoten in höheren Ebenen weniger Ausgangskanten nötig, der Baum wird insgesamt kleiner. Die beiden letzten Optimierungen setzen jedoch eine Analyse der Abonnentenmenge vor dem Baumaufbau voraus. D. Lösung durch endliche Automaten Im folgenden wird eine Zusammenfassung des Artikels „Efficient Recognition of Events in a Distributed System“ [2] wiedergegeben. 1. Lösungsansatz/weitere Annahmen Auch dieser Ansatz benötigt einige einschränkende Annahmen. Ein jeder Abonnent wird wieder als Konjunktion von Prädikaten angesehen. Prädikate sind ebenfalls Tests auf genau einem Attribut des Artikels. Für die Attribute wird eine feste Reihenfolge vorausgesetzt. Jede Konjunktion soll genau k Prädikate beinhalten. Don’t care Fälle werden somit wieder benötigt. Die möglichen Werte eines Attributes werden als beliebige, nicht notwendigerweise beschränkte Menge angenommen. Jeder Abonnent kann als Grundlage für einen NFA gesehen werden. Dieser NFA besteht aus genau k Zustandsübergängen, wobei der i. Übergang genau vom i. Attribut abhängig ist. Ein jeder Nichtendzustand enthält einen Test, wie im anderen Ansatz ein jeder innerer Knoten. Ein Übergang stellt das Resultat eines Tests dar. Don’t Care Fälle sind direkt in -Übergänge übertragbar. Der NFA hat genau k+1 Zustände, wobei die ersten k die Tests enthalten und der Endzustand den Abonnenten beinhaltet. Hat die Abonnentenmenge Kardinalität n, gibt es n solche NFA’s. Diese können zu einem großen Automaten zusammengefasst werden. Er besteht aus n parallelen Pfaden, dessen sämtliche i. Übergänge Resultate eines Tests auf dem i. Attribut eines Artikels darstellen. Dieser NFA kann in einen DFA gewandelt werden. Mit diesem kann man einen Event testen, um die interessierten Abonnenten zu finden. Dabei müssen maximal k+1 Zustände besucht werden. Die Laufzeit wird somit eher von der Attributzahl als von der Abonnentenzahl abhängig sein. 2. Größe des Eingabealphabets für den Automaten Wie unter 1. erwähnt, kann die Kardinalität der Attributräume durchaus unbeschränkt sein. Es stellt sich also die Frage, ob die Theorie von endlichen Automaten, welche bekanntlich auf endlichen Alphabeten beruht, als Grundlage genommen werden kann. Aufgrund einer endlichen Abonnentenmenge, kann die Wertemenge eines jeden Attributes nur in eine endliche Zahl von Untermengen zerlegt werden. Denn ein jedes Prädikat kann die bisherige Anzahl von Teilmengen verdoppeln. Das tritt ein, falls jede Untermenge sowohl Elemente enthält für die der Attributtest stimmt, als auch welche, für die er nicht zutrifft. n Abonnenten können somit jede der Attributmengen in höchstens 2^n Teilmengen zerlegen. Bei k Attributen entstehen also maximal k*2^n Teilmengen. Das ist nur die theoretische Obergrenze. Gleichheitstests zerlegen eine jede Attributmenge in maximal n+1 disjunkte Teilmengen. Bei Bereichstests gibt es im schlimmsten Fall k*2*n Untermengen. Eine Ordnung auf der Menge wird hier vorausgesetzt. Für jede eindeutige Untermenge wird ein Symbol benötigt. Somit ist das Alphabet für unseren Automaten, trotz der beliebigen Attributmengen, ein endliches. Schlimmstenfalls hat es eine Dimension von k*2^n. 3. Transformation von NFA zu DFA Ein klassischer Automat hat für alle seine Zustände ein gemeinsames großes Eingabealphabet. Dieses setzt sich aus der Vereinigung der Alphabete jedes Zustands zusammen, wobei eventuell Umbenennungen vorgenommen werden 1 {1,2,3} x müssen. Für unser Problem stellt es einen a e i m Vorteil dar, die Alphabete eines jeden Zustands einzeln zu betrachteten. Dadurch kann ein anderer als der klassische {1,2,3} x 1 b f j Algorithmus zur Umwandlung des n nichtdeterministischen in den s deterministischen Automaten angewendet werden. Dessen Unterschied liegt zum 0 {1,2,3} y c g k o einen darin, dass nicht alle Alphabetsymbole von jedem Zustand aus betrachtet werden müssen. Lediglich die des jeweiligen Teilalphabets sind möglich. 0 {1,2,3} y d h l p Andere führen per Definition in die leeren Zustandsmenge. Ein weiterer Unterschied Bild2. NFA liegt in der Erzeugung von {a,b,c,d} {e,f} {g,h} {i} {j} {k} {l} { i, j} 1a {e, f} {} {} {} {} {} {} {} 0 {g, h} {} {} {} {} {} {} {} 1 {} {i} {} {} {} {} {} {} 2 {} {i, j} {k} {} {} {} {} {} 3 {} {i} {l} {} {} {} {} {} 4 {} {j} {k} {} {} {} {} {} 5 {} {j} {l} {} {} {} {} {} x {} {} {} {m} {n} {} {} {m, n} y {} {} {} {} {} {o} {p} {} Bild3. Klassische Konstruktionsmethode {a,b,c,d} {1} { e, f } {e,f} {1,3} {i} {2} { i, j } {g,h} {2,4} {k} {3,5} {l} {i} { i, j} {0} { g, h } {4,5} {j} {x} {m} {x} { m, n } {x} {n} {y} {k} {o} {y} {l} {p} Bild4. Optimierte Methode {j} - Folgezuständen. In der klassischen Version wird jedes Symbol des Alphabets einzeln betrachtet und jeweils die Menge der Folgezustände erzeugt. In der optimierten Version wird durch effizientes Einsetzen eines Algorithmus gleich die Symbolmenge, die in die selbe Zustandsmenge abbildet, gefunden. Dann muss nicht für jedes Alphabetsymbol einzeln die Folgezustandsmenge gesucht werden, sondern nur für ein Element der gefundenen disjunkten Teilmengen von Symbolen. Die Bilder3 und 4 zeigen die beiden Algorithmen am Beispiel des nichtdeterministischen Automaten aus Bild2. Das Hauptproblem bei der Umsetzung des Verfahrens liegt darin, die Teilmengen von Symbolen, welche in die gleiche Zustandsmenge abbilden, zu finden. Diese Mengen müssen bei Vereinigung die verwendeten Alphabetsymbole in der betrachteten Zustandsmenge des NFA ergeben. Dazu wird folgender effiziente Algorithmus von den Autoren [2] vorgeschlagen. Das Verfahren ist jedoch nur für Mengen- und Gleichheitstests anwendbar. Der Algorithmus besteht aus 2 Schritten. Der erste funktioniert folgendermaßen: - Markiere jede Originalalphabetmenge eines Übergangs der Zustandsmenge mit einem eindeutigen Einheitsvektor. (Dieser muss mindestens die Dimension m haben, wenn es m Übergänge in dieser Zustandsmenge im NFA gibt.) Trage jedes Symbol jeder Originalalphabetmenge in eine Hashtabelle ein. Nutze dabei die Elemente als Schlüssel und die Vektoren als Werte. Tritt ein Konflikt bei gleichen Schlüsseln auf, so verknüpfe deren beiden Vektoren mit einem logischen ODER und ersetze den bisherigen Vektor des Schlüssels. Löse Konflikte bei verschiedenen Schlüsseln z.B. mit einer verketteten Liste. In der erzeugten Hashtabelle ist nun für jedes Element verzeichnet, in welcher Originalalphabetmenge es vorhanden war. Für einen jeden entstandenen Vektor muss ein Übergang im DFA bereitgestellt werden. Bei Abarbeitung des Automaten kann in dieser Tabelle nachgeschaut werden, welchem Übergang bei einem Eingabesymbol zu folgen ist. Dies ist in konstanter Zeit möglich [3]. Der zweite Schritt tut nun folgendes: - Trage jedes Element der erzeugten Hashtabelle in eine weitere Hashtabelle ein. Nutze den assoziierten Vektor als Schlüssel und das Element als Wert. Tritt ein Konflikt bei gleichen Schlüsseln auf, vereinige das vorhandene Element (Menge) mit dem neuen und speichere diese Menge als Wert des Schlüssels. Anderenfalls löse den Konflikt durch eine verkettete Liste. In dieser zweiten Hashtabelle sind jetzt die gesuchten disjunkten Teilmengen, die einen Zustandsübergang im DFA bilden, enthalten. Das Erzeugen beider Hashtabellen ist in linearer Zeit zur Summe der Mächtigkeiten der Originalalphabetmengen möglich. Dies basiert auf Hashtabellen mit Durchschnittszeiten zum Einfügen und Auslesen in konstanter Zeit [3]. Eine weitere Besonderheit weist der Transformationsalgorithmus auf. Da in jedem Zustand ein Test auf genau einem Attribut ausgeführt werden soll, dürfen keine Zustände mit Tests aus unterschiedlichen Attributen zusammengefasst werden. Dieses Zusammenfassen tritt bei Übergängen in der Standardmethode auf. Deshalb müssen diese Fälle hier anders behandelt werden. Anstatt einen Zustand mit dem einer anderen b b Ebene zu vereinigen, wird diese spätere Ebene in alle Nichtepsilon-Übergänge dieses c c a a Zustands integriert. Zusätzlich wird ein d Übergang (durch gekennzeichnet), welcher bei Zutreffen keiner der anderen Kanten verfolgt e d d wird, eingefügt. Bild5 soll dies verdeutlichen. e e 4. Aufwandsanalyse: Bild5. Wandelung DFA in NFA Als Maß für die Laufzeit wird die Zahl der Tests im DFA angenommen. Es werden Analysen für verschiedene Arten von Tests betrachtet. Diese sind zu den bisher betrachteten als jeweilig zusätzlich anzusehen. n soll im folgenden die Anzahl der Abonnenten und k die Zahl der Prädikate sein. a) nur Gleichheitstests Im besten Fall liegt auf dem Weg durch den DFA nur ein Zustand, welcher zwei Übergänge besitzt. Alle anderen haben genau einen Übergang (und den Übergang in die leeren Zustandsmenge). Es müssen hier k+1 Ergebnisse betrachtet werden. Dieser Fall tritt ein, wenn alle anderen Abonnenten, aufgrund eines Unterschieds Bild6. worst case Pfad in einem Attribut, nicht möglich sind. Bild7 zeigt dieses. Im schlechtesten Fall liegen die Abzweigungen zu den anderen Zuständen (Abonnenten) alle auf dem Weg durch den Automaten. Dann müssen (n-1)+k mögliche Ergebnisse getestet werden. Das Ergebnis ist nicht zufriedenstellend, da es linear mit der Abonnentenzahl steigt. Eine einfache Verbesserung spiegelt sich jedoch extrem in der Laufzeit Bild7. best case Pfad wieder. Durch Sortieren der möglichen Symbole in den Zuständen und Nutzung von binärer Suche kann der Aufwand auf O(k * log n) verkleinert werden. (Durch den Einsatz von Hashtabellen wäre sogar Linearität zur Attributanzahl gegeben.) In Bild6 sind 2 Möglichkeiten dieses Falls zu sehen. b) don’t care Fälle Die mögliche Unabhängigkeit von einem Attribut verschlechtert die Laufzeit des Algorithmus nicht. Ein don’t care Fall stellt bei NFA einen -Übergang dar. Bei der Transformation zum DFA werden diese Übergänge eliminiert. Es bleibt lediglich eine zusätzliche Möglichkeit bei jedem Zustand erhalten. Es existiert ein Übergang (), welcher benutzt werden muss, falls kein anderer in Frage kommt. Dadurch entfällt wiederum der Übergang in die leere Zustandsmenge. Somit müssen im schlechtesten Fall die gleiche Anzahl von Vergleichen durchgeführt werden. Die Laufzeit bleibt also gleich. c) Mengentests Im schlimmsten Fall können 2^n-1 Übergänge je Zustand entstehen. Diese Zahl ist die maximal mögliche Anzahl von Kombinationen aus den n Zuständen je Ebene. Tritt dieser pathologische Fall in allen Ebenen des Automaten auf, ergibt sich ein Gesamtaufwand von O(k * 2^n). Der oben unter 3. erklärte Algorithmus mit Nutzung von Hashtabellen kann den Aufwand auf O( k ) verringern. d) Bereichstests Bei Nutzen von Bereichen können 2*n-1 Übergange je Zustand entstehen. Diese Zahl ergibt sich, wenn der Bereich eines jeden Abonnenten den bisherigen Bereichen genau 2 hinzufügt. Also einen bereits vorhandenen in 3 Bereiche zerlegt. Summiert ergibt sich im schlechtesten Fall eine Komplexität von O(n * k). Durch Einsetzen von binärer Suche kann wieder eine Verbesserung der Laufzeit auf O(k * log n) erreicht werden. e) Speicherplatz Der benötigte Platz für einen Automaten hängt von seiner Zustandszahl und der Anzahl der Übergänge ab. Wie unter c) analysiert gibt es maximal 2^n-1 Zustände pro Ebene. Da es k+1 Ebenen im DFA gibt, liegt der maximale Speicherbedarf bei O( k * 2^n ). f) Zeit zum Aufbau Die Aufbauzeit ist auch direkt von der Zustandszahl des erzeugten DFA’s abhängig. Es ergibt sich analog zu e) ein Maximalaufwand von O( k * 2^n ). 5. Optimierungen Die schlechtesten Fälle beim Abarbeiten des DFA ergeben sich nur dann, wenn die Hauptzahl der Abonnenten ein gemeinsames Präfix besitzt. Ziel ist es, ein solches gemeinsames Präfix so klein wie möglich zu halten. Eine Umsortierung der Prädikate hat keinen Einfluss auf das Endergebnis, da laut Definition ein Abonnent eine Konjunktion von Prädikaten darstellt. Deren Reihenfolge ändert das Resultat nicht. Eine Betrachtung der Abonnenten vor Erzeugen des NFA’s könnte diese Minimierung der gemeinsamen Präfixe durch Umsortieren durchführen. Im DFA würden dann viele Abonnenten in frühen Zuständen in unterschiedliche Pfade eingetragen werden. Dadurch entfallen die Betrachtungen ihrer Prädikatergebnisse dann auf einem Weg durch den Automaten. Ob diese Art der Sortierung jedoch in allen Fällen zum gewünschten Erfolg führt, möchte ich bezweifeln. Eine Sortierung nach Anzahl der möglichen Attributwerte steht einer Problemlösung wohl näher. Dadurch wird erreicht, dass durch eine minimale Anzahl von Vergleichen viele Abonnenten in andere Pfade eingetragen werden, wodurch Vergleiche mit ihren anderen Attributen entfallen. Eine andere Verbesserung kann durch Verlagerung der zeitintensiven Bereichstests an das Ende des Automaten gelingen. Diese Tests würden dann auf einem kleineren Alphabet ausgeführt werden und somit weniger Laufzeit benötigen. Führt man sie schon früh im Automaten aus, müssen viele mögliche Ergebnisse betrachtet werden, da sämtliche durch diesen Knoten erreichbaren Abonnenten zu beachten sind. E. Wertung der Ansätze 1. Einschränkung des Profils Die Einschränkung des Profils auf Konjunktionen stellt eine Beschneidung der Möglichkeiten dar. Zwar ist {,} funktional vollständig, jedoch ist man durch eine weitere Festlegung beschränkt. Dadurch, dass jedes Prädikat von genau einem Attribut abhängig sein muss, können nicht alle Anfragen mit der Sprache definiert werden. a) Integration von ODER Um die Profilsprache nicht der von beiden Ansätzen vorausgesetzten Einschränkung der bloßen Verwendung von Konjunktionen zu unterwerfen, könnte man die Ansätze wie folgt erweitern. Zur Nutzung eines logischen ODER, ist es nötig einen Abonnenten vielfach in die interne Struktur einzutragen. Dabei muss so verfahren werden, dass jeweils alle bis auf eine der Disjunktionen anstatt einen bestimmten Wert zu fordern, als don’t care Fall betrachtet werden. Der Abonnent mit den Tests ( a=1 b=2 ) c=3 müsste z.B. als a=* b=2 c=3, als auch als a=1 b=* c=3 eingetragen werden. Da bei komplizierten Ausdrücken eine große Zahl dieser verschiedenen Möglichkeiten existiert, müssten eventuell kleinere Einschränkungen dieser Komplexität gemacht werden, zwingend notwendig ist es jedoch nicht. Durch die Mehrfacheintragung steigt die Größe der internen Struktur zur Darstellung der Abonnenten, welche sich für das System wie eine Erhöhung der absoluten Abonnentenzahl auswirkt. Dementsprechend würde sowohl Zeit als auch Speicherverbrauch ansteigen. Die Möglichkeit einer Verknüpfung durch ODER auf ein und demselben Attribut ist in beiden Fällen durch die Anwendung eines Tests auf Vorhandensein in einer Menge schon integriert. b) Integration von NOT Durch die Möglichkeit der Integration einer Verknüpfung der Attribute in den Profilen durch ein logischer ODER, sollte es nun möglich sein, den Einsatz eines NOT zu erzeugen. Durch Umformung einer beliebigen booleschen Formel, ist es möglich diese mit den 3 Operatoren ,, darzustellen. Diese Darstellung kann man in DNF wandeln und nun alle entstandenen Konjunktionen als einzelne Abonnenten eintragen. Jede dieser eingetragenen Konjunktionen ist von allen Attributen abhängig und zwar durch genau einen Test oder kann durch don’t care Fälle aufgefüllt werden. Die Negationen stehen nun jeweils vor einem Test. Diese entgegengesetzte Testart könnte dann in das System übernommen werden, falls sie noch nicht vorhanden ist. Also sind nun alle Formen von booleschen Anfragen möglich. c) Reihenfolge der Attribute Beide Ansätze gehen von einer vorgegebenen Reihenfolge und der Abhängigkeit jedes Abonnenten von allen Attributen aus. Diese Einschränkungen sind jedoch unkritisch, da sie für den Abonnenten als Nutzer des Systems gar nicht sichtbar sein müssen. Er kann frei sein Profil erstellen. Nach dem Abgeben der Spezifikationen kann das System die Reihenfolge seiner Prädikate verändern, natürlich unter Beachtung der Äquivalenz der Umwandlung. Vom Nutzer nicht eingeschränkte Attribute können durch einen don’t care Fall ersetzt werden. Somit sind alle engen Anforderungen des Systems auch bei einer weiter gefassten Profilsprache gegeben. Auf der anderen Seite sind die eintreffenden Dokumente zu sehen. Ihre Attribute müssen ebenfalls in der vorgegebenen Reihefolge vorhanden sein. Praktisch dürfte das schwer von der Vielzahl der Anbieter zu erwarten sein. Eine Sortierung müsste durchgeführt werden. Diese ist in O( k * log k) bei k Attributen möglich. Der praktisch damit verbundene Aufwand sollte jedoch nicht zu groß eingeschätzt werden, da eventuell sowieso Anpassungen der Attribute der verschiedenen Anbieter von Informationen vorgenommen werden müssen. Die Sortierung also „nebenbei“ passieren könnte. 2. Probleme beim Ansatz Matching Tree a) verschiedene Arten von Tests Der Algorithmus zum Baumaufbau verfolgt bei Vorhandensein unterschiedlicher Arten von Tests eine einfache und für den Suchaufwand ineffiziente Strategie. Soll ein anderer Test, als der im aktuellen Knoten vorhandene, ausgeführt werden, wird einfach *-Kanten gefolgt. Und zwar so lange, bis man den richtigen Test oder einen Knoten ohne *-Kante findet. Diesem Knoten fügt man dann eine solche Kante hinzu und trägt den Test in einen neuen Knoten ein. Aufgrund dieser Strategie sind sehr große Baumhöhen möglich, was zu höheren Suchzeiten führt. Eine andere Möglichkeit verschiedene Tests zu integrieren ist es, diese als gleichartige darzustellen. Bei Gleichheits- und Mengentests ist das ohne weiteren möglich. Bereichstests wiederum, könnte man als Mengentests betrachten. Bei kleinen Bereichen kann das angebracht sein. Liegen jedoch große Unterschiede zwischen dem Minimum und dem Maximum, so hätte man extrem große Mengen zu verwalten. Ein Mehrverbrauch an Speicher und größere Suchzeiten wären die Folge. Auch die andere Richtung gestaltet sich problematisch. Grosse Mengen würden im Extremfall pro Element genau einen Bereich erzeugen. Die Folgen für Speicher und Laufzeit wären die gleichen. Im Artikel [2] wird vorgeschlagen, Bereichstests pro unterschiedlichem Testbereich als andere Art von Test anzusehen. Damit hätte jeder dieser Tests genau 2 Kanten. Eine, der gefolgt wird wenn das Attribut des Events im Bereich liegt und eine *-Kante. Damit ergibt sich erstens eine sehr große Baumhöhe und zweitens die daraus resultierende größere Suchzeit, da stets beiden Kanten zu folgen ist. Andererseits könnte man die Bereiche als Kanten der Knoten eintragen. Dann müsste man aber eventuell mehreren dieser Kanten folgen. Auch so würde die Suchzeit extrem verlängert. Schließlich wäre es bei überlappenden Bereichen auch möglich, eine vorhandene Überschneidung durch Aufsplitten dieser, aufzuheben. Dann müssen Abonnenten jedoch in mehrere Blätter eingetragen werden. Die Knotenzahl läge dann im schlimmsten Fall exponentiell zur Abonnentenzahl. b) Laufzeitbeweis Als Laufzeit für das Finden der an einem Artikel interessierten Abonnenten, wurde als durchschnittlicher Wert O(k‘ * (ln k‘ + ln V) * [ |S| ^ (1-)] ) gezeigt. V ist die Zahl der möglichen Werte pro Attribut, S die Menge der Abonnenten, k‘ die Attributanzahl + 1 und eine von V und k beeinflusste Konstante. Der Beweis ist in der zugrundeliegenden Arbeit [1] in Abschnitt 4 zu finden. Zu diesem muss noch einmal erwähnt werden, dass nur Gleichheitstests der Attribute vorausgesetzt wurden. Das gefundene Ergebnis ist logarithmisch von der Anzahl der möglichen Werte V für ein Attribut abhängig. Diese Anzahl stellt nicht die Menge der möglichen Werte, bei den in den Baum eingetragenen Abonnenten dar, sondern die tatsächliche Mächtigkeit des zugrundeliegenden Alphabets je Attribut. Die Alphabete können also nicht als unbeschränkte Mengen angesehen werden. Beim Ansatz mit endlichen Automaten gibt es diese Einschränkung nicht. Praktisch ist diese Beschränkung jedoch im System gegeben, wenn auch in einer entsprechenden Größenordung. Ebenfalls wurde beim Beweis eine Gleichverteilung der möglichen Werte angenommen. In der Praxis ist das nicht anzunehmen. Ein Beispiel soll die daraus resultierenden Folgen aufzeigen. Nehme man für V eine große Zahl an. Bei simplen Tests auf Zeichenketten ist das ohne weiteres möglich. Theoretisch geht der -Wert dadurch nahe an 1. Der zu erwartende Exponent ist dann nahe 0. Erklärbar ist dieses Ergebnis dadurch, dass bei Gleichverteilung sehr viele Abonnenten, auf einem bestimmten Weg durch den Baum, vom Pfad abzweigen. In der Praxis hingegen ist es nicht unüblich, dass viele Abonnenten bei einem Attribut die gleichen Werte verlangen. Tritt dann auch nur bei einem von diesen Abonnenten im nächsten Attribut ein don’t care Fall auf, müssen alle diesem Pfad folgenden Events, mehrere Kanten parallel betrachten und somit Tests ausführen. Erstens ist also keine Gleichverteilung gegeben und zweitens hat ein häufig auftretender Fall schlechtere Laufzeiten als die selteneren. Die im Beweis getroffenen theoretischen Annahmen unterscheiden sich somit von der Praxis gravierend, und es ist fraglich, ob die gefundenen Werte in realen Systemen haltbar sind. F. Vergleich der Algorithmen 1. Effizienz Im folgenden wird versucht ein Vergleich zwischen den beiden Ansätzen hinsichtlich Speicherverbrauch und Laufzeit anzustellen. Die Lösung mit Aufbau eines Matching Tree wird im folgenden als Ansatz a und die Idee über endliche Automaten als Ansatz b bezeichnet. Beide Algorithmen zerlegen das Problem in 2 Teile. Dabei wird im ersten eine innere Datenstruktur aufgebaut, anhand derer die späteren Betrachtungen stattfinden. Ansatz b hat beim Aufbau dieser Struktur ein klares Defizit. Sowohl benötigter Speicher als auch Aufbauzeit liegen hier im exponentiellen Bereich zur Abonnenten- und Attributzahl. Bei Ansatz a hingegen ist der Aufwand proportional zum Produkt dieser beiden Werte. Wie unter E analysiert ist dieses Ergebnis jedoch nur bei Gleichheitstests zu erwarten. Der Automat hat in diesem Fall eine maximale Zustandszahl im Bereich Abonnentenanzahl ^ Attributanzahl, was immer noch ein vielfaches mehr ist. Es wäre jedoch vorstellbar, dass der Automat nur in großen Zeitintervallen neu aufgebaut wird. Eine tägliche Aktualisierung der Struktur wäre, aufgrund der vorhandenen Problemstellung, wahrscheinlich ausreichend. Das Problem des Speicherbedarfs könnte entweder durch große Hauptspeicher, oder durch ein Auslagern von Teilen der Struktur in den Hintergrund, gelöst werden. Da auf jedem Weg durch den DFA, die Zahl der besuchten Zustände der Anzahl der Attribute entspricht, könnte man bei jedem Event mit maximal dieser Zahl von Plattenzugriffen auskommen. Der andere wichtige Vergleichswert für die Effizienz ist die benötigte Zeit, um zu einem Artikel alle interessierten Abonnenten zu finden. Ansatz a braucht hierzu Zeit proportional zur Attributanzahl und sublinear zur Anzahl der Abonnenten. Der Exponent ist von Art und Menge der Attribute abhängig. Wie unter E. aufgezeigt, ist dieser Wert, wenn überhaupt, lediglich für Gleichheitstests annehmbar. Ansatz b hat hier einen großen Vorteil. Bei dieser Einschränkung ist das Finden der Abonnenten sogar von deren Gesamtzahl unabhängig. Lediglich die Zahl der Attribute geht als linearer Faktor ein. Auch bei anderen Testarten kommt bloß ein zusätzlicher Faktor logarithmisch zur Abonnentenzahl hinzu. Durch verschiedene Möglichkeiten der Optimierung sind bei beiden Ansätzen Verbesserungen der Laufzeit und Änderungen des benötigten Speichers zu erreichen. Eine theoretische Analyse des dabei zu erwartenden Aufwands ist nur schwer möglich. Praktische Vergleiche der Suchzeiten sind dann wohl besser geeignet, um Aussagen über das Verhalten bei tatsächlich vorhandenen Problemstellungen zu geben. 2. Lösungsansatz Beide Verfahren sehen es als geeignet an, eine interne Repräsentation des vorhandenen Problems zu erstellen. Auf deren Grundlage sollte es dann effizienter möglich sein, die Abonnenten zu finden, als beim unter B. genannten „einfachen“ Algorithmus. Ebenso gehen beide Ansätze in der Definition der zu verwendenden Profilsprache in die gleiche Richtung. Ihnen ist jeweils gemeinsam, dass sämtliche Abonnenten ihre Auswahlkriterien als Konjunktion von Einschränkungen der Attribute angeben müssen. Die Struktur der zur Suche erstellten internen Darstellung des Problem ist bei beiden Ansätzen eine ähnliche. Sowohl der Automat, als auch der Matching Tree, stellen eine Art Suchbaum dar. Lediglich in dessen Optimierung liegen die Unterschiede. Ansatz b versucht die Struktur soweit als möglich dahingehend zu optimieren, dass beim Suchen die minimal nötige Anzahl von Baumknoten besucht werden muss. Diese liegt in der Anzahl der Attribute. Die don’t care Fälle werden während des Erzeugens betrachtet und nicht erst beim späteren Arbeiten auf dem Automaten. Die Struktur erhält dadurch mehr Knoten, was auf Kosten von Speicherplatz und Erzeugungszeit geht. Ansatz a versucht die Baumstruktur in eine andere Richtung zu optimieren. Das Hauptziel liegt darin, einen geeigneten Mittelwert zwischen Suchzeit und Aufbauzeit zu finden. Der Speicherbedarf soll linear zur Abonnentenzahl sein. Dafür wird eine Verschlechterung der Suchzeit in Kauf genommen, wobei diese unter der des „einfachen“ Algorithmus liegen soll. Der Hauptunterschied der beiden Ansätze liegt somit nur auf der Optimierungsrichtung der jeweils erstellten internen Datenstruktur. Ansatz b baut dabei auf die Automatentheorie auf. Das vorhandene Ausgangsproblem ist leicht durch einen nichtdeterministischen Automaten darzustellen. Dessen, aufgrund der Problemstellung entstehende Struktur führt dazu, dass beim äquivalenten DFA auf jedem Pfad maximal so viele Zustände liegen, wie es Attribute gibt. Also ist durch dessen Erzeugen eine nur von der Attributzahl abhängige Lösung gefunden. Diese Umwandlung des Automaten ist die Hauptarbeit des Algorithmus. Die dafür benötigte Zeit ist direkt in die Erstellungszeit übertragbar. Aufgrund der Vielzahl von Zustandskombinationen, welche bei der Umwandlung entstehen können, leiten sich die im schlechtesten Fall entstehenden Zahlen für Speicher und Aufwand her. Diese Vielzahl von Kombinationen ist besonders wegen der nötigen Eliminierung von *-Kanten zu erreichen. Ansatz a löst diese nicht auf, sondern nimmt es in Kauf, jeweils mehreren Kanten folgen zu müssen. Würde man den Matching Tree als Automaten betrachten, wären zwar alle Übergänge mit eindeutigen Werten gekennzeichnet, jedoch gibt es noch -Übergänge. Er stellt quasi einen NFA dar, der teilweise in einen DFA umgewandelt wurde. G. Möglichkeiten der Aktualisierung der Datenstrukturen Beide hier vorgestellten Algorithmen verfolgen hinsichtlich der Veränderung der erzeugten Datenstrukturen den gleichen Ansatz. Es wird davon ausgegangen, dass sich die Profile der Abonnenten nur selten verändern bzw. neue hinzukommen oder verschwinden. In diesem Fall wird der gesamte Baum/DFA neu erzeugt (jedenfalls werden in beiden Arbeiten keine anderen Ansätze kundgetan). Deshalb soll im folgenden versucht werden solche Möglichkeiten zu analysieren. 1. Grundlage Matching Tree Bei den folgenden Betrachtungen wird jeweils von einer unoptimierten Version des Matching Tree ausgegangen. Am einfachsten ist das Hinzufügen eines neuen Abonnenten zu realisieren. Dieses wird beim Aufbau des Baumes ohnehin mit jedem Abonnenten getan. Somit kann sogar der Standardalgorithmus verwendet werden können. Über die sich daraus ergebende Ineffizienz bei verschiedenen Tests bzw. Ergebnisüberlappungen wird auf Abschnitt E verwiesen. Die Laufzeit ist proportional zur Baumhöhe. Das Entfernen eines Abonnenten kann wie folgt geschehen. Am einfachsten ist es, wenn er nicht der einzige Eintrag in einem Blatt ist. Dann kann man den Abonnenten einfach aus der Menge streichen. Sonst geht man im Baum schrittweise Richtung Wurzel, bis ein Knoten mit mindestens zwei Kindern gefunden wird. Aus diesem entfernt man dann die Kante, welche auf dem Weg zu ihm passiert wurde. Problematisch ist es, wenn dieser Knoten nur noch eine *-Kante enthält. Dann kann er aus dem Baum entfernt werden und sein Kind wird an seine Stelle gesetzt. Eventuell tritt nun der gleiche Fall erneut auf, die Lösung bleibt die selbe. Der entstehende Aufwand ergibt sich proportional zur Baumhöhe. Änderungen sind nun zum einen durch Kombination der beiden genannten Operationen möglich. Sinnvoll ist das nur, wenn die Änderung auch auf dem ersten Attribut der gegebenen Reihenfolge stattfand. Anderenfalls sollte man beim Entfernen darauf achten, dass nur solche Knoten gelöscht werden, die Tests auf „größeren“ als dem „kleinsten“ geänderten Attribut beinhalten. Ab dieser „kleinsten“ Änderung kann dann das Einfügen erfolgen. So erspart man sich ein Löschen und Hinzufügen von Knoten mit letztendlich gleichem Inhalt. Eine Änderung (Löschen, Einfügen, Update) des Baumes jeglicher Art kann somit in Zeit proportional zur Baumhöhe geschehen. Die Datenstruktur könnte einmal erzeugt werden und danach nur noch durch Änderungen in ihrer Struktur erneuert werden. 2. Grundlage endliche Automaten Beim Ansatz mit endlichen Automaten gestalten sich die Operationen zur Änderung schwieriger. Wir wollen zuerst das Entfernen eines Abonnenten betrachten. Gibt es mehrere 1..3 Abonnenten der gleichen Art, so kann er einfach aus der Menge A1,A3 4..6 im Endzustand entfernt werden. Anderenfalls geht man so lange in Richtung Startzustand, bis ein Zustand mit mindestens 2 A4,A5 7..9 Übergängen erreicht wird. Der überwundene Pfad kann dann entfernt werden. Allerdings ist der Abonnent jetzt möglicherweise noch nicht vollständig aus dem Automaten Bild8. Entfernen eines Abonnenten entfernt. Es ist möglich, dass Zustände, welche auf dem Weg zu dem entfernten Abonnenten liegen, noch Tests enthalten, welche aufgrund des entfernten Zustandes bestehen. Folgendes Beispiel anhand von Bild8 soll das zeigen. Der Test überprüft Bereiche. Wird Abonnent A3 entfernt, so ist dessen ehemaliger Zweig überflüssig. Er könnte entfernt und mit dem oberen vereint werden. Dieser würde dann den Bereich 1..6 abdecken. Solche Probleme könnten bei allen Zuständen auftreten. Diese zu analysieren würde zeitlich nicht möglich sein, da mindestens alle Endzustände betrachtet werden müssen. Deren Zahl liegt schlimmstenfalls im exponentiellen Bereich zur Abonnentenzahl. Eine andere Möglichkeit wäre es, in jedem Zustand bei jedem Testergebnis zu speichern, aufgrund welcher Abonnenten es entstanden ist. Die Analyse würde dann zwar beschleunigt, jedoch der Speicheraufwand noch weiter steigen. Die einfachste Lösung ist jedoch, diesen Fakt zu ignorieren und den Baum erst nach dem Entfernen von einer größeren Zahl von Abonnenten neu zu erzeugen, um die unnötigen Vergrößerungen zu eliminieren. Auch das Einfügen bringt erwartungsgemäß Probleme mit sich. Ist bereits ein Abonnent mit gleichen Prädikaten in den Automaten eingetragen, so trifft man beim Durchlaufen auf einen Endzustand. Zu diesem fügt man den neuen Abonnenten hinzu. Trifft man auf dem Weg durch den Automaten auf ein noch nicht behandeltes Testergebnis, gibt es zwei Möglichkeiten. Bestenfalls gibt es keinen Übergang, dem bei allen nichtverzeichneten Fällen zu folgen ist. Dann kann man einfach das Testergebnis zum Zustand hinzufügen und die restlichen Tests ebenso. Gibt es diesen Übergang, muss der gesamte von ihm ausgehende Pfad kopiert werden und dann in diesen weiter eingetragen werden. Das gleiche Problem ergibt sich beim Aufsplitten eines Testergebnisses in verschiedene Fälle. Da schlechterdings exponentiell zur Abonnentenzahl viele Zustände zu kopieren sind, erhält das Problem eine entsprechende exponentielle Größe. Insgesamt gestaltet sich das Problem der Aktualisierung beim DFA also schwieriger, da der Aufwand ins exponentielle gehen kann. Der Matching Tree mit linearer Zeit zur Baumhöhe hat dabei klare Vorteile. Eine Aktualisierung der Struktur einmal am Tag stellt jedoch eine mögliche Alternative dar, welche auch praktisch keine Hindernisse schaffen sollte. A1 Quellen/Material: [1] M.K. Aguilera, R.E. Strom, Dw.C. Sturman, M. Astley and T.D. Chandra: Matching events in a content-based subscription system. Proceedings of the 18th ACM symposium on Principles of distributed computing May 1999. [2] K.J. Gough, G. Smith: Efficient Recognition of Events in a Distributed System. Proceedings of the ACSC-18, 1995 [3] Thomas H. Cormen, Charles E. Leiserson and Ronald L. Rivest Introduction to Algorithms. The MIT Electrical Engineering and Computer Science Series, The MIT Press, 1990