Mit der fortschreitenden Digitalisierung von Alltagsgegenständen und ihrer Verbindung mit dem Internet wächst das sogenannte Internet of Things. Dadurch sind auch immer mehr offene Systeme online verfügbar, die ihre Sensordaten und Zustandsinformationen als RDF\footnote{Ressource Description Framework --- Mehr dazu in Kapitel \ref{cpt:basics}}-Datenstrom anbieten. Diese Ereignisdatenströme liefern durchgehend und hochfrequent Ereignisdaten, sodass innerhalb kurzer Zeit sehr große Datenmengen anfallen, die zwecks Extraktion von Informationen und Auslösen von Reaktionen innerhalb kürzester Zeit verarbeitet werden sollen.
Die Ereignisdaten aus diesen Strömen bilden kleine Teile der Realität zumindest nä\-herungs\-wei\-se über die in ihnen enthalten Messdaten und Zustandsinformationen ab, sofern sie nicht bedingt durch technischen Defekt oder Messfehler ungültige Daten enthalten und somit zur Verarbeitung ungeeignet sind. Ein weiteres Problem ist die stark begrenzte Gültigkeit von Ereignisdaten: Oft werden sie schon durch ein neu aufgetretenes Ereignis hinfällig und sind nicht mehr aktuell.
Ereignisse haben für sich alleine betrachtet eine begrenzte Aussagekraft und Gültigkeit, daher ist es zum höheren Verständnis der dahinter verborgenen Situation notwendig, sie mit den zuvor aufgetretenen Ereignissen in einen Kontext zu setzen. Dadurch können mehrere Ereignisse zu komplexen Ereignissen aggregiert werden und mittels Mustererkennung höherwertige Informationen aus den Ereignissen extrahiert werden.
Die Integration von Domänenwissen\footnote{Hintergrundwissen für den Kontext der Ereignisverarbeitung, verändert sich während der Verarbeitung nur selten} ist ein weiterer Schritt, der die Brücke zwischen den aus komplexen Ereignissen gewonnenen Kenntnissen und bereits bekannten Fakten schlagen soll, um die gewonnenen Kenntnisse in einen eindeutigen Zusammenhang stellen und eine eindeutige Interpretation ermöglichen.
Um unter diesen Bedingungen viele Ereignisdatenströme mit hochfrequenten Ereignissen in nahezu Echtzeit zu verarbeiten ist CEP\footnote{Complex-Event-Processing} das Mittel der Wahl: Mit CEP werden die Ereignisse der verschiedenen Datenströme für begrenzte Zeiträume im Speicher vorgehalten und innerhalb von sogenannten Sliding-Windows betrachtet. Dabei können Ereignismuster erkannt werden und verschiedene Ereignisse aggregiert werden um neue komplexe Ereignisse zu erzeugen.
Ziel dieser Arbeit ist die Einführung in die Konzepte von CEP und RDF, sowie die Demonstration der praktischen Nutzung der CEP-Engine \enquote{C-SPARQL} zur Verarbeitung von RDF-Datenströmen am Beispiel einer Autoverleihgesellschaft zur Überwachung von Leihfahrzeugen. Auch soll ergründet werden, welche technischen Möglichkeiten existieren, um Reasoning auf RDF-Datenströmen zu betreiben --- eine Technik, die Erkenntnisse aus den Ereignisströmen durch Anstellung von Schlussfolgerungen auf den Daten der Datenströme extrahiert.
Diesbezüglich soll ergründet werden, welche CEP-Engines Reasoning bereits implementieren und wie weit ihre technischen Möglichkeiten reichen --- eine große Herausforderung, da die mit einzubeziehenden Ereignisdaten sich kontinuierlich verändern.
\todo{Eventuell platziere ich die Details des Szenarios vor das Konzept-Kapitel und halte die Beschreibung allgemeiner? --- Jap, so könnte es gehen. Dann wird hier nur grob erklärt, welche Daten für das Szenario interessant sind; die einzelnen Datenströme und Formate der Ereignisse kommen dann in das Konzept-Kapitel.}
Das bereits erwähnte Beispielszenario, welches für diese Arbeit verwendet wird, ist eine Autoverleihgesellschaft, die ihren Fuhrpark überwachen möchte, um ihren Kunden vergünstigte Tarife für verschleißarmes Fahrverhalten anbieten zu können. Weiterhin soll auf plötzlich auftretende Probleme an den Leihwagen möglichst schnell reagiert werden können um Schäden zu begrenzen, gefährliche Situationen zu vermeiden und bei Bedarf dem Kunden unverzüglich einen Ersatzwagen oder weitere Serviceleistungen anbieten zu können. Um dies zu erreichen, werden zwei RDF-Datenströme zur späteren Verarbeitung eingerichtet.
Wird einem Kunden ein Auto zugewiesen oder gibt ein Kunde ein geliehenes Auto wieder zurück, so wird hierfür ein Ereignis in diesen Datenstrom eingespeist. Diese Ereignisse enthalten immer eine eindeutige Kundennummer und die Nummer des geliehenen Fahrzeugs.
Um die Ereignisdaten aus den beiden beschriebenen Datenströmen bei der Verarbeitung in einen eindeutigen Kontext setzen zu können, wird lokal verfügbares Hintergrundwissen benötigt. Dieses enthält für dieses Szenario folgende Informationen:
\todo{In der Motivation wurde grob erklärt, warum jetzt CEP das Mittel der Wahl sein soll. Aber was bedeutet das eigentlich? Was ist denn CEP und was ist RDF? Das kommt in diesem Kapitel.}
\todo{Mehr Fachbegriffe nutzen und früher einführen}
\todo{Da wir CEP auf RDF-Datenströmen betreiben wollen kommt jetzt erst einmal eine Einführung in die bisher typische Welt von RDF, der dazugehörigen Abfragesprache SPARQL und ein kleiner Ausblick auf die Fähigkeiten von Reasoning.}
Das Ressource Description Framework (RDF) wird im semantischen Web zur Modellierung und Beschreibung von Wissen verwendet. RDF-Daten bestehen aus einer Menge von Tripeln, welche sich aus den drei Komponenten Subjekt, Prädikat und Objekt in genau dieser Abfolge zusammensetzen. Jeder dieser drei Bestandteile eines Tripels wird durch einen eindeutigen Uniform Resource Identifier (URI\footnote{Der URI wird in RFC 3986 beschrieben. Anstelle eines URI kann auch ein IRI (Internationalized Resource Identifier) verwendet werden --- die internationalisierte Form des URI nach RFC 3987.}) identifiziert.
Das in Listing~\ref{lst:sample_rdf_triple} enthaltene Tripel ordnet das Auto-Subjekt \texttt{\#23} über das Prädikat \texttt{isCarModel} dem Objekt Automodell \texttt{\#42} zu.
Wie anhand des Beispiels erkennbar ist, ist die explizite Notation für Tripel aufgrund der häufigen Nennung von vollständigen URIs wenig platzsparend und für große Datenmengen somit nicht empfehlenswert. Hierfür bietet sich die Nutzung von Prefixen an, die nach einmaliger Definition innerhalb eines Kontextes (zum Beispiel einer Datei) verwendet werden können.
Listing~\ref{lst:sample_rdf_triple_with_prefix} zeigt die Notation von Tripeln im Turtle\footnote{Siehe auch die Spezifikation der Turtle-Notation nach \cite{w3c:turtle}}-Format unter Verwendung von Prefixen.
Über Prädikate können diesem Subjekt mit Spezifikation im Objekt-Teil des Tripels bestimmte Attribute mit Werten zugesprochen werden oder Verknüpfungen mit anderen Subjekten hergestellt werden.
Aufgrund der Flexibilität dieser Struktur ist es möglich, nahezu jede Art von Informationen auf Tripel abzubilden, wie Listing~\ref{lst:sample_rdf_data} an einem Beispiel zeigt.
Da innerhalb des semantischen Web angestrebt wird, in RDF vorliegende Informationen gemeinsam zu nutzen, miteinander zu kombinieren und vernetzen zu können, werden RDF-Tripel meist als Quadrupel gehandhabt, in denen als zusätzliche Information der sogenannte Graph genannt wird, in dem die Tripel enthalten sind. Ein Graph wird durch eine URI identifiziert und dient somit als Namensraum für die Tripel, die er enthält. Dies vereinfacht die gleichzeitige Nutzung von mehreren Datenquellen, da jedes Tripel eindeutig einem Graphen zugeordnet werden kann und innerhalb von Abfragen spezifisch Tripel aus verschiedenen Graphen kombiniert werden können.
Zusätzlich werden im semantischen Web in OWL (Web Ontology Language) formulierte Ontologien als \enquote{Strukturgerüst} verwendet. Eine Ontologie definiert ein Vokabular mit logischen Domänenobjektklassen und bestimmt für diese Objektklassen Prädikate und Attribute, um bestimmte Sachverhalte eindeutig abbilden zu können. Eine Ontologie für Listing~\ref{lst:sample_rdf_data} würde beispielsweise eine Objektklasse \enquote{person} definieren, auf welches die eigenen Prädikate \enquote{isGender}, \enquote{hasName} und \enquote{hasSibling} angewandt werden können. Mit eigenen Attributen für das Prädikat \enquote{isGender} und spezifischen Regeln dafür, welche Attribute ein Prädikat wie \enquote{hasSibling} in Frage kommen können, werden Daten aus der Welt einer Ontologie --- ähnlich wie bei einem relationalen Datenbankschema --- eindeutig strukturiert. Hierbei ist jedoch wichtig hervorzuheben, dass für in RDF abgebildete Daten nahezu immer die Annahme gilt, dass diese Daten nicht vollständig sind (die sogenannte \enquote{Open World Assumption}). Die meisten Ontologien respektieren diese Annahme und verzichten auf die Definition von expliziten Regeln, die über die konkrete Bedeutung der Abwesenheit von bestimmten Fakten entscheiden würden.
Weiterhin ist es möglich, beliebig viele verschiedene Ontologien gleichzeitig zu verwenden. Diese Flexibilität ermöglicht beispielsweise, dass eine bereits in RDF abgebildete Person durch beliebige Informationen mit weiteren Ontologien ergänzt werden kann, oder dass die Informationen einer abgebildeten Person in verschiedenen, für andere Parteien geläufigen Strukturen verfügbar gemacht werden können. Auch kann innerhalb einer Ontologie auf Objektklassen und Attribute zurückgegriffen werden, die in anderen Ontologien definiert werden. Dies ermöglicht neben Erweiterungen für spezifische Zwecke auch das Übersetzen von Wissen zwischen verschiedenen Ontologien.
Die Abfrage von RDF-Daten erfolgt über die Sprache SPARQL (\enquote{SPARQL Protocol And RDF Query Language}), welche in diesem Abschnitt grob erläutert wird. Eine detaillierte Beschreibung von SPARQL ist unter \cite{w3c:sparql} nachzulesen.
Im Gegensatz zu Abfragesprachen von relationalen Datenbanksystemen wie SQL ist es mit SPARQL möglich, Daten über verschiedene Datenquellen wie Tripel- oder Quadstores hinweg miteinander zu verknüpfen. Auch ist im Gegensatz zu SQL keine spezielle Anpassung der Abfragen an ein Datenbankschema notwendig; lediglich die Art und Weise, wie die angeforderten Daten miteinander in Verbindung stehen, ist für SPARQL-Abfragen wichtig. Im Folgenden zeigt Listing~\ref{lst:sample_sparql_query} eine einfache Abfrage auf den Daten aus Listing~\ref{lst:sample_rdf_data}.
Listing~\ref{lst:sample_sparql_query} zeigt, dass SPARQL in der groben Grundstruktur eine Ähnlichkeit zu SQL aufweist; allerdings sind bedingt durch die Struktur der Daten (Relationen bei SQL gegenüber Tripel und Quadrupel bei SPARQL) große Unterschiede in der Gestaltung der Abfragen --- speziell in der \texttt{WHERE}-Klausel --- zu finden: Hier werden Tripel mit Platzhaltern verwendet, um aus dem vorhandenen Datenbestand die Tripel zu isolieren, die auf das angegebene Muster passen. So wird in diesem Beispiel ein beliebiges Subjekt (gekennzeichnet durch \texttt{?marie}) gesucht, welches gleichzeitig vom Typ Person ist, den Namen \enquote{Marie} trägt und einen bisher unbekannten Bruder (\texttt{?brother}) hat, der einen noch unbekannten Namen (\texttt{?nameOfBrother}) trägt. Für jedes Subjekt, auf welches diese Beschreibung passt, ergibt sich nun ein Ergebnis, welches die in der \texttt{SELECT}-Klausel angegebenen Felder zurückgibt --- in diesem Fall also lediglich ein Ergebnis mit dem Wert \enquote{Max}.
Neben \texttt{SELECT} unterstützt SPARQL auch das Schlüsselwort \texttt{CONSTRUCT}. Dieses ermöglicht die direkte Konstruktion von neuen Tripeln aus vorgegebenen Tripeln mit Platzhaltern, welche mit den Ergebnissen der Abfrage gefüllt werden. Listing~\ref{lst:sample_sparql_construct} zeigt die Erzeugung von Tripeln für Geschwister, die auf ihren jeweilige Schwester (\enquote{isSisterOf}) beziehungsweise ihren jeweiligen Bruder (\enquote{isBrotherOf}) zeigen.
Durch den Einsatz von Ontologien ergibt sich die Möglichkeit, auf RDF-Daten Ontologie-gestützt Schlussfolgerungen anstellen zu können (\enquote{Reasoning}). In diesem Prozess werden aus den in RDF-Daten vorhandenen Fakten (Assertion Box, kurz: ABox) und den in den verwendeten Ontologien definierten Objektklassen, Regeln und Zusammenhängen (Terminology Box, kurz: TBox) neues Wissen abgeleitet \cite{hitzler:semanticweb} und die lokale Datenbasis damit angereichert. So können beispielsweise implizite Klassentypen errechnet werden (Ein Kind ist eine Person), oder regelbasierte Attribute ermittelt werden: Max fährt ein Fahrzeug + das Fahrzeug ist ein Kran $\Longrightarrow$ Max ist ein Kranführer.
Enthält eine Ontologie Informationen über verschiedene Verwandtschaftsgrade in Familien, so ist es beispielsweise möglich auf Basis der Daten aus Listing~\ref{lst:sample_rdf_data} zusätzliche Verbindungen wie \enquote{isBrotherOf} und \enquote{isSisterOf} zu errechnen. Limitiert werden diese Möglichkeiten lediglich durch die OWA (Open World Assumption), also die Annahme einer offenen Welt, über die unvollständiges Wissen vorliegt. Deshalb dürfen für Reasoning nur explizit bekannte Fakten genutzt werden: Nur weil in Listing~\ref{lst:sample_rdf_data} keine Informationen über Eltern vorhanden sind, heißt das erst einmal nicht, dass Max und Marie wirklich Waisenkinder sind. Weiterführende Beispiele zu den Möglichkeiten von OWL Reasoning finden sich unter \cite{man:owl}.
Da Ontologien auch genutzt werden können, um Wissen aus den Strukturen einer Ontologie in die Struktur einer anderen Ontologie zu übersetzen, kann ein Reasoner die daraus resultierende Übersetzung direkt errechnen und der lokalen Datenbasis hinzufügen. Dadurch steht Abfragen, die schon auf die Ziel-Ontologie zugeschnitten sind, ein viel größerer Informationspool zur Verfügung, aus dem das Abfrageergebnis berechnet werden soll.
Diesen Vorteil erkauft man sich durch einen nicht unerheblichen Einsatz von Rechenleistung, da im Prozess des Reasoning eine Menge von zusätzlichen Daten entsteht, für die zusätzlich zu den bereits vorhandenen Daten die Regeln aller genutzten Ontologien berücksichtigt werden müssen. Behandelt man lediglich statische Daten, die sich kaum bis garnicht ändern, so ist der nötige Aufwand für Reasoning übersichtlich und liegt auch für große Mengen von Daten und Ontologien in einem akzeptablem Rahmen. Ändern sich jedoch häufig Daten, so muss für das Subset der sich geänderten Daten der Reasoning-Prozess erneut durchgeführt werden um eine vollständig aktuelle Datenbasis zu erhalten.
Im folgenden Abschnitt wird ein kurzer Einstieg in das Konzept von Complex Event Processing (CEP) gegeben. Eine detailreiche Erläuterung von CEP und die beispielhafte Anwendung der CEP-Engine \enquote{Esper} wird in \cite{hsh:cep} beschrieben.
Wie der Begriff \enquote{Complex Event Processing} schon andeutet, geht es bei CEP um die Verarbeitung von komplexen Ereignissen --- konkret: Die Erkennung und Erfassung von komplexen Ereignissen aus Datenströmen von primitiven Ereignissen. Von Messereignissen aus mit Sensoren ausgestatteten Geräten über Transaktionen im Handel bis hin zu Benutzerinteraktionen auf Webseiten entstehen täglich unzählig viele, primitive Ereignisse, die abhängig von ihrem Kontext für einen bestimmten Zeitraum ein Stück der echten Welt korrekt abbilden.
Die in diesen primitiven Ereignissen enthaltenen Informationen stellen nur einen momentanen Zustand dar; sie haben für sich alleine betrachtet keinen Kontext und somit vorerst bedeutungslos. Betrachtet man beispielsweise ein Ereignis \enquote{Die gemessene Temperatur beträgt 42°C.}, so ist zunächst nicht zu erkennen, was es mit dieser Temperatur auf sich hat. Hier kommt das für die Verarbeitung bereits bekannte \emph{Hintergrundwissen} (auch Domänenwissen) ins Spiel, welches das Ereignis in einen bekannten Kontext stellen kann. Es kann uns beispielsweise verraten, dass die Ereignisquelle ein Temperatursensor ist, der sich in einem PKW auf dem Motorblock befindet. Das Hintergrundwissen kann zu der bekannten Umgebung des Sensors viele weitere Angaben enthalten: Das konkrete Fabrikat des PKW, dessen Höchstgeschwindigkeit und die maximal zulässige Betriebstemperatur des Motors. Dieses Wissen ermöglicht schon eine genaue Einordnung der Informationen des Ereignisses; allerdings werden doch noch weitere Informationen benötigt, um ein eindeutiges Bild der Gesamtsituation zu erhalten. Kombiniert man das Temperaturereignis mit den Meldungen des im PKW installierten Geschwindigkeitssensors, so ergibt sich die Möglichkeit herauszufinden, ob für den aktuellen Betriebszustand des PKW die gemessene Motortemperatur.
Ein weiterer, wichtiger Faktor ist der Zeitraum in dem bestimmte Ereignisse auftreten. Um dies näher zu erläutern, betrachten wir den gegebenen Ereignisstrom aus Listing~\ref{lst:sample_eventstream}.
\begin{lstlisting}[caption={Exemplarischer Ereignisstrom: Motortemperatur eines PKW},label={lst:sample_eventstream}]
Auf den ersten Blick ist ersichtlich, dass die Messwerte einen sehr starken Temperaturanstieg abbilden, jedoch fehlt eine Angabe darüber, wie viel Zeit zwischen diesen Ereignissen vergangen ist. Dadurch ist die Interpretation dieser Ereignisse nicht mehr eindeutig möglich: Liegen zwischen den Messereignissen beispielsweise etwa 30-60 Minuten, so könnte es sich um einen normalen Betrieb bei hoher Geschwindigkeit handeln. Sollten jedoch nur wenige Minuten zwischen den Messereignissen vergangen sein, so lassen die Messwerte auf einen Defekt schließen und ein Motorschaden wäre eine mögliche Folge. Die Zeitachse darf somit bei der Ereignisverarbeitung nicht vernachlässigt werden.
Ein weiterer Kernaspekt von CEP ist die Mustererkennung in Ereignissen. Aus bestimmten primitiven Ereignissen, die in einer bestimmten Abfolge auftreten, soll ein konkreter Sachverhalt abgeleitet werden. Treten bei einem PKW beispielsweise in kurzer Zeit nacheinander die Ereignisse \enquote{Motor abgeschaltet}, \enquote{Fahrzeug verriegelt} und \enquote{PKW beschleunigt} auf, so könnte der Fall eingetreten sein, dass ein gerade abgestelltes Fahrzeug losgerollt ist und es sollte unverzüglich eine Reaktion darauf gestartet werden.
Insgesamt liegt die Herausforderung von CEP darin, in kürzester Zeit große Datenströme von Ereignissen mit Hintergrundwissen anzureichern, diese zu höherwertigen Ereignissen zu kombinieren und bestimmte Muster zu finden, sowie die Ergebnisse mit möglichst geringer Verzögerung in Echtzeit ausgeben zu können oder Reaktionen einzuleiten.
Um Ereignisse aus verschiedenen Quellen gemeinsam zu verarbeiten ist RDF als kleinster gemeinsamer Nenner für Informationen das Mittel der Wahl. Hierbei werden die Ereignisse gegebenenfalls vorher in das RDF-Format transformiert und als Datenstrom aus RDF-Quadrupeln der CEP-Engine zugeführt. Die Quadrupel führen neben den ereignisrelevanten Informationen zusätzlich noch den Zeitstempel mit, zu dem das Ereignis ausgelöst wurde.
Als Abfragesprache für die RDF-Datenströme kommt eine erweiterte Form von SPARQL --- im Folgenden \enquote{CSPARQL} --- zum Einsatz, welche Erweiterungen und Funktionen speziell für die Verarbeitung von RDF-Datenströmen mitbringt. CSPARQL kann die eingehenden RDF-Datenströme in sogenannten \enquote{Sliding Windows} erfassen und ermöglicht die Berücksichtigung der Zeitstempel der Ereignisse innerhalb der Abfrage durch die Bereitstellung von zusätzlichen Sprachkonstrukten und Funktionen. Dabei besteht weiterhin die Möglichkeit, lokal in Form von RDF-Daten vorhandenes Domänenwissen in die Abfrage einzubeziehen und mit den Ereignisdaten zu verknüpfen.
In Listing~\ref{lst:sample_rdf_event} aufgeführt sind RDF-Tripel, die ein beispielhaftes Zustands-Ereignis aus einem PKW zeigen. Das Prefix \texttt{http://example.org/cars} wurde zu Zwecken der Übersichtlichkeit durch \texttt{cars:} abgekürzt.
\begin{lstlisting}[caption={Ereignis im RDF-Format},label={lst:sample_rdf_event}]
\todo{Noch ein wenig auf das Listing eingehen, URIs und die fiktiven Prädikate etwas erläutern}
\subsection{SPARQL-Erweiterung zur Verarbeitung von RDF-Datenströmen}
Der große Vorteil bei der Ereignisverarbeitung mit SPARQL auf RDF-Daten liegt in der Mächtigkeit dieser Abfragesprache: Innerhalb einer einzigen SPARQL-Abfrage ist es möglich Ereignisse aus verschiedenen Quellen miteinander zu kombinieren, direkt mit Hintergrundwissen zu kombinieren, nach eigenen Kriterien zu filtern, einfache Berechnungen anzustellen und aus dem Ergebnis neue Ereignisse beliebiger Struktur zu erzeugen.
Somit muss der Anwender neben SPARQL keine weiteren Sprachen lernen oder sich anderweitig mit der Implementierung der Engine auseinandersetzen, sondern kann sich komplett auf die zu analysierenden Ereignisse konzentrieren. Listing~\ref{lst:sample_combine_events_sparql} zeigt einen SPARQL-Query, in dem zwei aufeinanderfolgende Ereignisse mit Angaben zur Momentangeschwindigkeit eines Autos zu einem komplexeren Beschleunigungsereignis kombiniert werden.
\begin{lstlisting}[caption={Kombination von Ereignissen mit SPARQL},label={lst:sample_combine_events_sparql}]
\item Verarbeitet Ströme im RDF-Format. Kann Hintergrundwissen im RDF-Format einbeziehen. In Java implementiert und entsprechend auch recht einfach in Java-Projekte zu integrieren.
\item Timestamp-Funktionalität zur Zeit mit einem Bug versehen, aber generell immernoch nutzbar.
\item Integration von Hintergrundwissen und Abfragen über mehrere Streams kombiniert möglich.
\todo{Warum jetzt eigentlich C-SPARQL? Weil es in Java fährt, auf Jena basiert und somit echt komfortabel in der Handhabung ist. Und trotzdem kommen noch akzeptable Ergebnisse mit minimalem Support für RDFS-Reasoning raus. Dadurch ist es für Einsteiger gut geeignet und bietet dennoch schon solide Features durch CSPARQL.}
\todo{In diesem Kapitel werden abstrakte Condition-Action-Regeln für das Beispielszenario formuliert und dann mit konkreten \enquote{C-SPARQL}-CSPARQL-Queries umgesetzt. }
\todo{In diesem Kapitel wird die Engine konkret ausgepackt und mit Java-Code benutzt. Es werden Datenstromgeneratoren gezeigt, Queries registriert und und und und dann vielleicht etwas Reasoning eingeschaltet.}
Jetzt einen Query an der Engine registrieren; Ergebnis ist ein ResultProxy, an den Observer angeklemmt werden können um die Query-Ergebnisse weiter zu verarbeiten.
Im Main-Thread einfach etwas Thread.sleep() callen und in den am ResultProxy angehangenen Observern die Ergebnisse entsprechend auswerten und weiter verarbeiten.
Spezielle Betrachtung der StreamGenerators und wie sie funktionieren, Anmerkungen darüber, dass hier Daten von außen gezogen und ggf. konvertiert werden können.
\item Wie steht es um Reasoning? Geht das? Wenn ja, nur RDFS oder auch OWL? \todo{Ist der Unterschied zwischen den Beiden fürs erste sehr wichtig oder führt das zu weit?}
Mit \enquote{enquote} wird Text in Anführungszeichen gesetzt, aber manchmal ist vielleicht der Einsatz von \texttt{texttt} sinnvoll. Im \textbf{Notfall} kann auch \textbf{textbf} genutzt werden. Dann gibt es noch \textit{textit}, \textsc{textsc}, \textsf{textsf} und \textsl{textsl}.