[TASK] Generic commit.

This commit is contained in:
Jan Philipp Timme 2016-10-11 17:52:57 +02:00
parent 7993b7d68b
commit e30c8b467e

View File

@ -927,12 +927,7 @@ GROUP BY (?car)
\end{lstlisting}
\section{Einbindung von Domänenwissen}\label{cpt:integrating_knowledge}
Zur Einbindung von lokalem Domänenwissen bietet C-SPARQL sehr leicht zugängliche Möglichkeiten. Bevor das lokale Domänenwissen in C-SPARQL-Queries zur Verfügung steht, muss es zunächst in einen Graphen geladen werden. Der folgende Code liest die in der Date \texttt{data/carSimulationABox.rdf} gespeicherten RDF-Daten und hinterlegt sie für die Engine in dem Graphen \texttt{http://example.org/carSimKnowledgeGraph}:
\begin{lstlisting}
engine.putStaticNamedModel("http://example.org/carSimKnowledgeGraph",
CsparqlUtils.serializeRDFFile("data/carSimulationABox.rdf"));
\end{lstlisting}
Um auf diese Daten aus einem C-SPARQL-Query zugreifen zu können, ist es lediglich notwendig, den Graphen mit einer zusätzlichen \texttt{FROM}-Klausel als Datenquelle anzugeben:
Zur Einbindung von lokalem Domänenwissen in einem Query bietet C-SPARQL die Möglichkeit, auf Daten aus lokal angelegten Graphen zuzugreifen. Bevor das lokale Domänenwissen in C-SPARQL-Queries zur Verfügung steht, muss es zunächst in einen Graphen geladen werden. Wie dies geschieht, wird in Kapitel~\ref{cpt:csparql_domain_knowledge} beschrieben. Sind nun Daten in dem Graphen mit der URI \path{http://example.org/carSimKnowledgeGraph} hinterlegt worden, so ist der Zugriff aus einem C-SPARQL-Query heraus leicht: Es ist lediglich notwendig, den Graphen mit einer zusätzlichen \texttt{FROM}-Klausel als Datenquelle anzugeben:
\begin{lstlisting}
FROM <http://example.org/carSimKnowledgeGraph>
\end{lstlisting}
@ -955,7 +950,7 @@ Die Verknüpfung von Ereignisdaten mit lokalem Domänenwissen ist bei der Nutzun
\section{Reasoning auf RDF-Datenströmen}
Die C-SPARQL-Engine unterstützt die automatische Anreicherung von RDF-Da\-ten\-strö\-men und Abfrageergebnissen durch implizites Wissen, welches durch ein gegebenes RDFS-Vokabular abgeleitet werden konnte. Hierfür wird in der C-SPARQL-Engine die Implementierung des \texttt{GenericRuleReasoner} aus Apache Jena verwendet. Diesem Reasoner wird ein Regelwerk zugeführt, welches die Axiome und Folgerungsregeln von RDFS implementiert. Somit ist die Engine in der Lage, auf RDF-Datenströmen Reasoning durchzuführen, um diese um implizites Wissen anzureichern. Der praktische Nutzen daraus ist höhere Flexibilität bei der Formulierung von C-SPARQL-Queries; insbesondere die automatische Anreicherung von Ereignisinstanztypen aus Hierarchien von Objektklassen kann Generalisierungen von CEP-Regeln deutlich vereinfachen. Hierzu ein Beispiel:
Die C-SPARQL-Engine unterstützt die automatische Anreicherung von RDF-Da\-ten\-strö\-men und Abfrageergebnissen durch implizites Wissen, welches durch ein gegebenes RDFS-Vokabular abgeleitet werden konnte. Somit ist die Engine in der Lage, auf RDF-Datenströmen Reasoning durchzuführen, um diese um implizites Wissen anzureichern. Der praktische Nutzen daraus ist höhere Flexibilität bei der Formulierung von C-SPARQL-Queries; insbesondere die automatische Anreicherung von Ereignisinstanztypen aus Hierarchien von Objektklassen kann Generalisierungen von CEP-Regeln deutlich vereinfachen. Hierzu ein Beispiel:
\todo{...}
Gegeben sei folgende TBox mit Vokabular im RDF-Schema:
\begin{lstlisting}[label={reasoning_tbox},caption={TBox mit Klassen und Attributdefinitionen aus RDFS}]
@ -964,35 +959,18 @@ Gegeben sei folgende TBox mit Vokabular im RDF-Schema:
:CarBrakeWearEvent rdfs:subClassOf :CarWearEvent .
\end{lstlisting}
Kombiniert man diese nun in einem Reasoning-Prozess mit der folgenden ABox:
Diese wird nun in einem Reasoning-Prozess mit der folgenden ABox kombiniert:
\begin{lstlisting}[label={reasoning_abox},caption={ABox mit Fakten, die sich auf die TBox aus Listing~\ref{reasoning_tbox} beziehen}]
:SomeThing rdf:type :Thing .
\end{lstlisting}
Das Ergebnis hieraus sind folgende Tripel, die \emph{zusätzlich} zu den Tripeln aus der ABox nun zur Abfrage durch C-SPARQL-Queries zur Verfügung stehen:
\begin{lstlisting}[label={reasoning_result},caption={Durch Reasoning ermitteltes, implizites Wissen}]
TODO: ERGEBNIS
\end{lstlisting}
Um Reasoning mit der C-SPARQL-Engine zu nutzen, müssen die folgenden zwei Schritte durchgeführt werden:
\paragraph{Aktivierung der Inferenz}
Bei der Registrierung einer C-SPARQL-Abfrage an der Engine muss angegeben werden, ob Inferenz mit dem Reasoner für diesen Query verwendet werden soll. Die folgende Zeile zeigt diesen Schritt, wobei der zweite Parameter ausschlaggebend für die Aktivierung ist:
\begin{lstlisting}
CsparqlQueryResultProxy resultProxy = engine.registerQuery(query, true);
\end{lstlisting}
\paragraph{Konfiguration des Reasoners}
Hat man auf diese Weise einen Query an der Engine registriert, so muss als nächstes für den \texttt{CsparqlQueryResultProxy} Parameter angegeben werden, unter denen das Reasoning durchgeführt werden soll. Neben der Angabe des zu verwendenden Regelwerks, welches in diesem Fall RDFS implementiert, muss eine TBox mit Basisvokabular angegeben werden, die als Basis für die Schlussfolgerungen dient. Weiterhin ist es möglich zu konfigurieren, welche Logik zum Anstellen der Schlussfolgerungen verwendet werden soll. Hierbei gibt es drei Auswahlmöglichkeiten, die nun grob erklärt werden:
\begin{itemize}
\item \textbf{Forward Chaining}: Geht von den bereits existierenden Fakten aus und prüft anhand dieser Fakten, ob es Regeln gibt, die durch diese Fakten erfüllt sind. Ist dies der Fall, werden diese erfüllten Regeln verwendet, um daraus Wissen abzuleiten. Stellt das standardmäßige Vorgehen dar, falls keine Logik explizit angegeben wurde.
\item \textbf{Backward Chaining}: Stellt quasi das gegenteilige Vorgehen zu Forward Chaining dar. Begonnen wird bei einer Aussage, die darauf überprüft werden soll, ob sie zutrifft. Nun werden alle Regeln gesucht, die zu dieser Aussage führen und geprüft, ob diese erfüllt sind. Somit sind alle Bedingungen dieser Regeln wiederum Aussagen, die geprüft werden müssen. Dieser Ansatz setzt sich über weitere Regeln so weit fort, bis entweder ein erfüllender Fakt gefunden wurde, oder alle Regeln negativ getestet worden sind.
\item \textbf{Hybrid}: Ein Ansatz, welcher Forward Chaining und Backward Chaining kombiniert.
\end{itemize}
\todo{Erläuterung der praktischen Ergebnisse von Reasoning auf RDF-Datenströmen}
Die Details der technischen Implementierung von Reasoning in der C-SPARQL-Engine können in \cite{barbieri:reasoning} nachgelesen werden. Weiterführend kann über die Umsetzung von Reasoning mit Complex Event Processing in der Masterarbeit von Stefan Lier\cite{hsh:reasoning} gelesen werden.
Die technischen Details von Reasoning in der C-SPARQL-Engine werden in Kapitel~\ref{cpt:csparql_reasoning} beleuchtet.
\chapter{Umsetzung des Beispielszenarios}\label{cpt:csparql_in_practice}
Nachdem die Umsetzung von CEP-Regeln in C-SPARQL im vorherigen Kapitel erläutert wurde, soll nun das in Kapitel~\ref{cpt:scenario} angerissene Beispielszenario der Autoverleihgesellschaft umgesetzt werden. Gegeben hierfür sind zwei Ereignisdatenströme, eine lokale Wissensbasis (ABox) und ein grundlegendes Vokabular (TBox), welches Definitionen für die in der ABox und in den Ereignisdatenströmen verwendeten Objektklassen und Attributen enthält. Mit diesen Resourcen soll die Umsetzung der Anforderungen des Beispielszenarios Schritt für Schritt durchgeführt werden.
@ -1244,29 +1222,7 @@ WHERE {
?e car:relatedUser ?driver .
}
\end{lstlisting}
Registriert man diesen Query an der Engine, so kann man mit Hilfe eines in Java geschriebenen Observers die lokale Wissensbasis um Einträge aktualisieren, in denen der Fahrer eines PKW entsprechend eingetragen oder --- wenn man dieses Verfahren für Ereignisse vom Typ \texttt{CarReturnedEvent} umsetzt --- ausgetragen werden. Der folgende Abschnitt zeigt den Code eines solchen Observers:
\begin{lstlisting}[label={scenario_observer_sparql_update},caption={Aktualisierung von lokalem Domänenwissen via SPARQL UPDATE}]
Observer resultObserver = new Observer() {
@Override
public void update(Observable o, Object arg) {
RDFTable results = (RDFTable) arg;
Collection<RDFTuple> tuples = results.getTuples();
for(RDFTuple tuple : tuples) {
String driverUri = tuple.get(0);
String carUri = tuple.get(1);
String updateQuery = "PREFIX car: <http://example.org/carSim/carSimulationOntology#>"
+ "INSERT DATA { " // Use "DELETE DATA" to remove the entry again
+ " GRAPH <http://example.org/carSim/localDomainKnowledge> { "
+ " <"+driverUri+"> car:drives <"+carUri+"> . "
+ " <"+carUri+"> car:isDrivenBy <"+driverUri+"> . "
+ " } "
+ "}";
RentACarSimulation.logger.debug(updateQuery);
engine.execUpdateQueryOverDatasource(updateQuery);
}
}
};
\end{lstlisting}
Registriert man diesen Query an der Engine, so kann man mit Hilfe eines in Java geschriebenen Observers die lokale Wissensbasis um Einträge aktualisieren, in denen der Fahrer eines PKW entsprechend eingetragen oder --- wenn man dieses Verfahren für Ereignisse vom Typ \texttt{CarReturnedEvent} umsetzt --- ausgetragen werden. Die Details dazu finden sich in Kapitel~\ref{cpt:csparql_update_domain_knowledge}.
\paragraph{Zusammenfassung der Verschleißereignisse}
Um die einzelnen Ergebnisse aus den vorherigen Abfragen zusammenfassen zu können, ist zunächst erforderlich für die vier verschiedenen Ereignistypen eine gemeinsame Oberklasse \texttt{CarWearEvent} zu definieren. Hierzu werden der lokal vorliegenden TBox folgende RDFS-Daten hinzugefügt:
@ -1425,28 +1381,98 @@ Beobachtet man die Ergebnisse dieses Queries, so erfasst man PKW, die aufgrund e
\section{Nutzung der C-SPARQL Engine in Java}
Nachdem die C-SPARQL-Queries zur Umsetzung der Anforderungen des Beispielszenarios aus Kapitel~\ref{cpt:scenario} feststehen, muss nun das Szenario implementiert werden. Das CSPARQL-ReadyToGoPack\footnote{Zu beziehen unter \url{http://streamreasoning.org/resources/c-sparql}} diente hierbei als Referenz. Die für die C-SPARQL-Engine benötigten Abhängigkeiten werden dabei durch das Werkzeug Maven bezogen und bereitgestellt.
\paragraph{Initialisierung der Engine}
Zunächst wird eine Instanz der Engine benötigt. Diese kann über
\paragraph{Initialisierung der Engine}\label{cpt:csparql_domain_knowledge}
Zunächst wird eine Instanz der Engine benötigt. Diese muss dann initialisiert werden, wobei ein Parameter festlegt, ob die Funktion \texttt{f:timestamp(?s,?p?o)} zum Ermitteln der Zeitstempel von Tripeln aus Ereignisdatenströmen zur Verfügung stehen soll.
\begin{lstlisting}
CsparqlEngine engine = new CsparqlEngineImpl();
\end{lstlisting}
erzeugt werden. Darauf folgt eine Initialisierung, bei der ein Parameter festlegt, ob die Funktion \texttt{f:timestamp(?s,?p?o)} zum Ermitteln der Zeitstempel von Tripeln aus Ereignisdatenströmen zur Verfügung stehen soll.
\begin{lstlisting}
engine.initialize(true);
\end{lstlisting}
\paragraph{}
Als nächstes wird das lokale Domänenwissen aus einer RDF-Datei im Pfad \path{data/carSimulationAbox.rdf} geladen und in einem lokalen, benannten Graphen mit der URI \path{http://example.org/carSim/localDomainKnowledge} abgelegt:
\begin{lstlisting}
engine.putStaticNamedModel(
"http://example.org/carSim/localDomainKnowledge",
CsparqlUtils.serializeRDFFile("data/carSimulationABox.rdf"));
\end{lstlisting}
\paragraph{Registrierung der RDF-Ereignisdatenströme}
Nun werden die zu verarbeitenden Ereignisdatenströme benötigt; sie müssen an der Engine registriert werden. Im Kontext der C-SPARQL-Engine wird ein Ereignisdatenstrom durch die Klasse \texttt{RdfStream} repräsentiert. Dieser bekommt bei seiner Konstruktion die URI übergeben, unter der der Datenstrom innerhalb von C-SPARQL-Queries abgefragt werden kann. Über die öffentliche Methode \texttt{put(RdfQuadruple quad)} können Quadrupel an den Datenstrom geschickt werden, der diese wiederrum an die Engine weitergibt. Mit Hilfe der Methode \texttt{registerStream(RdfStream stream)} wird der Datenstrom an der Engine registriert. Es folgt ein Beispiel für die grundlegende Verwendung von der Klasse \texttt{RdfStream}:
\begin{lstlisting}
RdfStream myRdfStream = new RdfStream("http://example.org/stream/myStream");
engine.registerStream(stream);
myRdfStream.put(new RdfQuadruple(
":subject",
":predicate",
":object",
System.currentTimeMillis()
));
\end{lstlisting}
\paragraph{Registrieren von Queries an der Engine}
Nachdem die Ereignisdatenströme an der Engine registriert sind und das lokale Domänenwissen erfolgreich hinterlegt wurde, können die C-SPARQL-Queries an der Engine registriert werden. Hierzu wird der Query als String an die Methode \texttt{registerQuery(String query, boolean useInference)} übergeben, um einen \texttt{CsparqlQueryResultProxy} zu erhalten:
\begin{lstlisting}
String query = "...";
CsparqlQueryResultProxy resultProxy = engine.registerQuery(query, false);
\end{lstlisting}
\paragraph{C-SPARQL Query als Ereignisdatenstrom registrieren}
Handelt es sich bei dem zu registrierenden Query um einen Ereignisdatenstrom (zu erkennen an der Präambel \texttt{REGISTER STREAM}, sowie der Verwendung des Schlüsselwortes \texttt{CONSTRUCT}), so ist auf Seite des Java-Codes ein kleiner Umweg notwendig, um die Ergebnisse des Queries wieder in die Engine einzuspeisen. Hierfür wird ein \texttt{RDFStreamFormatter} benötigt, der unter Angabe der URI des Datenstroms konstruiert wird. Dieser wird an der Engine als weiterer Ereignisdatenstrom registriert und schließlich als Observer an den ResultProxy übergeben:
\begin{lstlisting}
RDFStreamFormatter rdfStreamFormatter = new RDFStreamFormatter(streamUri);
engine.registerStream(rdfStreamFormatter);
resultProxy.addObserver(rdfStreamFormatter);
\end{lstlisting}
Nachdem dies vollbracht ist, können neue C-SPARQL-Queries nun unter Angabe der URI des neu registrierten Datenstroms auf diesen zugreifen. Einer mehrstufigen Auswertungskette steht so nichts mehr im Wege.
\paragraph{Beobachten der Ergebnisse von Queries}
Um nun die Ergebnisse der registrierten Abfragen zu erhalten, erzeugt man einen \texttt{Observer}, der den durch die Registrierung des Queries erhaltenen ResultProxy beobachtet:
\begin{lstlisting}
Observer o = new Observer() {
@Override
public void update(Observable o, Object arg) {
CsparqlQueryResultProxy resultProxy = (CsparqlQueryResultProxy) o;
RDFTable results = (RDFTable) arg;
Collection<RDFTuple> tuples = results.getTuples();
}
};
resultProxy.addObserver(o);
\end{lstlisting}
Wie aus dem Code ersichtlich ist, erhält man für jedes Abfrageergebnis die dazu gehörige Instanz des \texttt{CsparqlQueryResultProxy}, sowie eine \texttt{RDFTable}, die die dazugehörigen Ergebnisse enthält. Somit ist das Einsammeln der Abfrageergebnisse für eine manuelle Verarbeitung kein großes Problem.
\paragraph{Aktualisierung von Domänenwissen}\label{cpt:csparql_update_domain_knowledge}
In einigen Situationen ist es notwendig, Informationen aus dem lokalen Domänenwissen anzupassen. Auch hierfür bietet die C-SPARQL-Engine Möglichkeiten durch die Nutzung von SPARQL Queries. Der folgende Abschnitt zeigt die Zusammenstellung und Ausführung eines Queries, der Daten in die lokale Wissensbasis einfügt:
\begin{lstlisting}
String updateQuery = "PREFIX car: <http://example.org/carSim/carSimulationOntology#> "
+ "INSERT DATA { "
+ " GRAPH <http://example.org/carSim/localDomainKnowledge> { "
+ " :Driver#1 car:drives :Car#2 . "
+ " :Car#2 car:isDrivenBy :Driver#1 . "
+ " } "
+ "}";
engine.execUpdateQueryOverDatasource(updateQuery);
\end{lstlisting}
Auch das Löschen von Daten aus der lokalen Wissensbasis stellt kein Problem dar; ersetzt man aus dem gezeigten Query das \texttt{INSERT DATA} mit einem \texttt{DELETE DATA}, so werden die Daten wieder aus dem lokalen Graphen entfernt. Auf diese Weise wird für das Beispielszenario aus Kapitel~\ref{cpt:scenario} das Tracking der Fahrer realisiert.
\paragraph{Aktivierung und Konfiguration von Reasoning}\label{cpt:csparql_reasoning}
Für die Umsetzung von Reasoning wird in der C-SPARQL-Engine die Implementierung des \texttt{GenericRuleReasoner} aus Apache Jena verwendet. Im Rahmen dieses Szenarios wird diesem Reasoner ein Regelwerk zugeführt, welches die Axiome und Folgerungsregeln von RDFS implementiert.
Um Reasoning mit der C-SPARQL-Engine zu nutzen, müssen die folgenden zwei Schritte durchgeführt werden:
\paragraph{Aktivierung der Inferenz}
Bei der Registrierung einer C-SPARQL-Abfrage an der Engine muss angegeben werden, ob Inferenz mit dem Reasoner für diesen Query verwendet werden soll. Die folgende Zeile zeigt diesen Schritt, wobei der zweite Parameter ausschlaggebend für die Aktivierung ist:
\begin{lstlisting}
CsparqlQueryResultProxy resultProxy = engine.registerQuery(query, true);
\end{lstlisting}
\paragraph{Konfiguration des Reasoners}
Hat man auf diese Weise einen Query an der Engine registriert, so muss als nächstes für den \texttt{CsparqlQueryResultProxy} Parameter angegeben werden, unter denen das Reasoning durchgeführt werden soll. Neben der Angabe des zu verwendenden Regelwerks, welches in diesem Fall RDFS implementiert, muss eine TBox mit Basisvokabular angegeben werden, die als Basis für die Schlussfolgerungen dient. Weiterhin ist es möglich zu konfigurieren, welche Logik zum Anstellen der Schlussfolgerungen verwendet werden soll. Hierbei gibt es drei Auswahlmöglichkeiten, die nun grob erklärt werden:
\begin{itemize}
\item Welche technischen Strukturen sieht die Engine vor,
\item wie werden Datenströme zugeführt,
\item wie werden Queries erzeugt, registriert und beobachtet,
\item was muss dabei beachtet werden, welche Fallstricke gibt es (zur Zeit)
\item wie wird Hintergrundwissen eingespeist und zur Laufzeit aktualisiert,
\item welche Schritte sind nötig um RDFS-Reasoning zu nutzen?
\item Und natürlich immer wieder mittendrin: Wie sehen die Ergebnisse aus, die dabei entstehen?
\item \textbf{Forward Chaining}: Geht von den bereits existierenden Fakten aus und prüft anhand dieser Fakten, ob es Regeln gibt, die durch diese Fakten erfüllt sind. Ist dies der Fall, werden diese erfüllten Regeln verwendet, um daraus Wissen abzuleiten. Stellt das standardmäßige Vorgehen dar, falls keine Logik explizit angegeben wurde.
\item \textbf{Backward Chaining}: Stellt quasi das gegenteilige Vorgehen zu Forward Chaining dar. Begonnen wird bei einer Aussage, die darauf überprüft werden soll, ob sie zutrifft. Nun werden alle Regeln gesucht, die zu dieser Aussage führen und geprüft, ob diese erfüllt sind. Somit sind alle Bedingungen dieser Regeln wiederum Aussagen, die geprüft werden müssen. Dieser Ansatz setzt sich über weitere Regeln so weit fort, bis entweder ein erfüllender Fakt gefunden wurde, oder alle Regeln negativ getestet worden sind.
\item \textbf{Hybrid}: Ein Ansatz, welcher Forward Chaining und Backward Chaining kombiniert.
\end{itemize}
Tiefgehende Details über die Implementierung von Reasoning in der C-SPARQL-Engine können in \cite{barbieri:reasoning} nachgelesen werden. Weiterführend kann über die Umsetzung von Reasoning mit Complex Event Processing in der Masterarbeit von Stefan Lier\cite{hsh:reasoning} gelesen werden.
\section{Bewertung/Ergebnis}