From 471fbdb8a68371afd86f917df69ac1177dac7c23 Mon Sep 17 00:00:00 2001 From: Jan Philipp Timme Date: Sun, 9 Oct 2016 18:04:03 +0200 Subject: [PATCH] [TASK] Enhance even further, allow custom observers per query. --- data/carSimulationABox.rdf | 12 +- .../jpt/csparqlproject/SimulationContext.java | 26 ++-- .../csparqlproject/misc/QueryContainer.java | 8 + .../lu/jpt/csparqlproject/rentacar/Car.java | 36 ++--- .../rentacar/RentACarSimulation.java | 146 ++++++++++++++---- 5 files changed, 166 insertions(+), 62 deletions(-) diff --git a/data/carSimulationABox.rdf b/data/carSimulationABox.rdf index 9534bbc..4dfa556 100644 --- a/data/carSimulationABox.rdf +++ b/data/carSimulationABox.rdf @@ -66,8 +66,8 @@ 2000 4300 - 2.9 - 3.2 + 29 + 32 B @@ -75,8 +75,8 @@ 800 1900 - 3.5 - 3.8 + 35 + 38 B @@ -84,8 +84,8 @@ 1400 2500 - 2.6 - 3.0 + 26 + 30 B diff --git a/src/main/java/lu/jpt/csparqlproject/SimulationContext.java b/src/main/java/lu/jpt/csparqlproject/SimulationContext.java index cd4fa94..363fc1a 100644 --- a/src/main/java/lu/jpt/csparqlproject/SimulationContext.java +++ b/src/main/java/lu/jpt/csparqlproject/SimulationContext.java @@ -15,7 +15,6 @@ import eu.larkc.csparql.core.engine.CsparqlQueryResultProxy; import eu.larkc.csparql.core.engine.RDFStreamFormatter; import lu.jpt.csparqlproject.gui.FancyTextObserverWindow; import lu.jpt.csparqlproject.misc.QueryContainer; -import lu.jpt.csparqlproject.misc.ReasoningTester; import lu.jpt.csparqlproject.rentacar.RentACarSimulation; /** @@ -147,7 +146,7 @@ public class SimulationContext { // DEBUGGING ONLY //ReasoningTester rt = new ReasoningTester(this.engine); // Spawn the whole simulation - this takes care of simulation-specific things - simulation = new RentACarSimulation(); + simulation = new RentACarSimulation(this.engine); // Register all the event streams // Register car event stream RdfStream carStream = simulation.getCarStream(); @@ -159,14 +158,16 @@ public class SimulationContext { this.registeredStreams.add(driverStream); Collection queriesToRegister = new ArrayList(); // Collect the queries to use! - queriesToRegister.add(RentACarSimulation.getStandingCarsStream()); - queriesToRegister.add(RentACarSimulation.getMovingCarsStream()); - queriesToRegister.add(RentACarSimulation.getStronglyAcceleratingCarsStream()); - queriesToRegister.add(RentACarSimulation.getStronglyBrakingCarsStream()); - queriesToRegister.add(RentACarSimulation.getEngineWearStream()); - queriesToRegister.add(RentACarSimulation.getBrakeWearStream()); - queriesToRegister.add(RentACarSimulation.getHandbrakeWearStream()); - queriesToRegister.add(RentACarSimulation.getTireWearStream()); + queriesToRegister.add(simulation.getStandingCarsStream()); + queriesToRegister.add(simulation.getMovingCarsStream()); + queriesToRegister.add(simulation.getStronglyAcceleratingCarsStream()); + queriesToRegister.add(simulation.getStronglyBrakingCarsStream()); + queriesToRegister.add(simulation.getEngineWearStream()); + queriesToRegister.add(simulation.getBrakeWearStream()); + queriesToRegister.add(simulation.getHandbrakeWearStream()); + queriesToRegister.add(simulation.getTireWearStream()); + queriesToRegister.add(simulation.getCarTakenEventsQuery()); + queriesToRegister.add(simulation.getCarReturnedEventsQuery()); // Now register each query appropriately! for(QueryContainer queryContainer : queriesToRegister) { CsparqlQueryResultProxy resultProxy = null; @@ -189,6 +190,11 @@ public class SimulationContext { Observer resultObserver = this.createResultObserverWindow(queryContainer.name); resultProxy.addObserver(resultObserver); } + // Attach custom observers to resultProxy if available + // These are used for SPARQL UPDATE queries on local domain knowledge + if(queryContainer.customObserver != null) { + resultProxy.addObserver(queryContainer.customObserver); + } this.queryResultProxies.add(resultProxy); SimulationContext.logger.info("Successfully registered query " + queryContainer.name + ": " + queryContainer); } catch (Exception e) { diff --git a/src/main/java/lu/jpt/csparqlproject/misc/QueryContainer.java b/src/main/java/lu/jpt/csparqlproject/misc/QueryContainer.java index 72434ab..eb665af 100644 --- a/src/main/java/lu/jpt/csparqlproject/misc/QueryContainer.java +++ b/src/main/java/lu/jpt/csparqlproject/misc/QueryContainer.java @@ -1,5 +1,7 @@ package lu.jpt.csparqlproject.misc; +import java.util.Observer; + import eu.larkc.csparql.common.utils.ReasonerChainingType; /** @@ -15,6 +17,7 @@ public class QueryContainer { public String ruleSet; public ReasonerChainingType reasonerChainingType; public boolean useObserverWindow; + public Observer customObserver; public QueryContainer(String name, String query, boolean isStream) { this.name = name; @@ -25,6 +28,7 @@ public class QueryContainer { this.ruleSet = "REASONING NOT PROPERLY ENABLED"; this.reasonerChainingType = null; this.useObserverWindow = false; + this.customObserver = null; } public void enableReasoning(String ruleSet, String TBox, ReasonerChainingType reasonerChainingType) { @@ -37,4 +41,8 @@ public class QueryContainer { public void useObserverWindow() { this.useObserverWindow = true; } + + public void useCustomObserver(Observer o) { + this.customObserver = o; + } } \ No newline at end of file diff --git a/src/main/java/lu/jpt/csparqlproject/rentacar/Car.java b/src/main/java/lu/jpt/csparqlproject/rentacar/Car.java index 37cb734..e803b0b 100644 --- a/src/main/java/lu/jpt/csparqlproject/rentacar/Car.java +++ b/src/main/java/lu/jpt/csparqlproject/rentacar/Car.java @@ -27,8 +27,8 @@ public class Car { private static final String[] REQUIRED_DRIVER_LICENSE = {"B", "B", "B"}; private static final int[] MIN_RPM = {2000, 800, 1400}; private static final int[] MAX_RPM = {4300, 1900, 2500}; - private static final double[] MIN_TIRE_PRESSURE = {2.9, 3.5, 2.6}; - private static final double[] MAX_TIRE_PRESSURE = {3.2, 3.8, 3.0}; + private static final int[] MIN_TIRE_PRESSURE = {29, 35, 26}; + private static final int[] MAX_TIRE_PRESSURE = {32, 38, 30}; // Generic stuff private int id; @@ -49,10 +49,10 @@ public class Car { private boolean motorOn; private int motorRpm; private int speed; - private double tirePressure1; - private double tirePressure2; - private double tirePressure3; - private double tirePressure4; + private int tirePressure1; + private int tirePressure2; + private int tirePressure3; + private int tirePressure4; private boolean checkEngineLightOn; @@ -108,10 +108,10 @@ public class Car { this.motorOn = false; this.motorRpm = 0; this.speed = 0; - this.tirePressure1 = 0*(Car.MIN_TIRE_PRESSURE[carType] + Car.MAX_TIRE_PRESSURE[carType]) / 2.0; - this.tirePressure2 = 0*(Car.MIN_TIRE_PRESSURE[carType] + Car.MAX_TIRE_PRESSURE[carType]) / 2.0; - this.tirePressure3 = 0*(Car.MIN_TIRE_PRESSURE[carType] + Car.MAX_TIRE_PRESSURE[carType]) / 2.0; - this.tirePressure4 = 0*(Car.MIN_TIRE_PRESSURE[carType] + Car.MAX_TIRE_PRESSURE[carType]) / 2.0; + this.tirePressure1 = (int) (Math.ceil((Car.MIN_TIRE_PRESSURE[carType] + Car.MAX_TIRE_PRESSURE[carType]) / 2.0)); + this.tirePressure2 = (int) (Math.ceil((Car.MIN_TIRE_PRESSURE[carType] + Car.MAX_TIRE_PRESSURE[carType]) / 2.0)); + this.tirePressure3 = (int) (Math.ceil((Car.MIN_TIRE_PRESSURE[carType] + Car.MAX_TIRE_PRESSURE[carType]) / 2.0)); + this.tirePressure4 = (int) (Math.ceil((Car.MIN_TIRE_PRESSURE[carType] + Car.MAX_TIRE_PRESSURE[carType]) / 2.0)); // State data this.currentState = CarState.LOCKED; this.currentAction = CarAction.NONE; @@ -191,16 +191,16 @@ public class Car { if(RandomHelper.isLuckyByChance(0.5)) { switch(RandomHelper.getRandomNumberWithin(1, 4)) { case 1: - this.tirePressure1 -= 0.1; + this.tirePressure1 -= 1; break; case 2: - this.tirePressure2 -= 0.1; + this.tirePressure2 -= 1; break; case 3: - this.tirePressure3 -= 0.1; + this.tirePressure3 -= 1; break; case 4: - this.tirePressure4 -= 0.1; + this.tirePressure4 -= 1; break; default: break; @@ -349,10 +349,10 @@ public class Car { this.quads.add(new RdfQuadruple(eventIri, baseOnt+"motorRPM", ""+this.motorRpm+"^^http://www.w3.org/2001/XMLSchema#integer", time)); this.quads.add(new RdfQuadruple(eventIri, baseOnt+"speed", ""+this.speed+"^^http://www.w3.org/2001/XMLSchema#integer", time)); this.quads.add(new RdfQuadruple(eventIri, baseOnt+"handbrakeEngaged", ""+this.handbrakeEngaged+"^^http://www.w3.org/2001/XMLSchema#boolean", time)); - this.quads.add(new RdfQuadruple(eventIri, baseOnt+"tirePressure1", ""+this.tirePressure1+"^^http://www.w3.org/2001/XMLSchema#double", time)); - this.quads.add(new RdfQuadruple(eventIri, baseOnt+"tirePressure2", ""+this.tirePressure2+"^^http://www.w3.org/2001/XMLSchema#double", time)); - this.quads.add(new RdfQuadruple(eventIri, baseOnt+"tirePressure3", ""+this.tirePressure3+"^^http://www.w3.org/2001/XMLSchema#double", time)); - this.quads.add(new RdfQuadruple(eventIri, baseOnt+"tirePressure4", ""+this.tirePressure4+"^^http://www.w3.org/2001/XMLSchema#double", time)); + this.quads.add(new RdfQuadruple(eventIri, baseOnt+"tirePressure1", ""+this.tirePressure1+"^^http://www.w3.org/2001/XMLSchema#integer", time)); + this.quads.add(new RdfQuadruple(eventIri, baseOnt+"tirePressure2", ""+this.tirePressure2+"^^http://www.w3.org/2001/XMLSchema#integer", time)); + this.quads.add(new RdfQuadruple(eventIri, baseOnt+"tirePressure3", ""+this.tirePressure3+"^^http://www.w3.org/2001/XMLSchema#integer", time)); + this.quads.add(new RdfQuadruple(eventIri, baseOnt+"tirePressure4", ""+this.tirePressure4+"^^http://www.w3.org/2001/XMLSchema#integer", time)); this.quads.add(new RdfQuadruple(eventIri, baseOnt+"locked", ""+this.isLocked+"^^http://www.w3.org/2001/XMLSchema#boolean", time)); } diff --git a/src/main/java/lu/jpt/csparqlproject/rentacar/RentACarSimulation.java b/src/main/java/lu/jpt/csparqlproject/rentacar/RentACarSimulation.java index bf7f21a..36c80f2 100644 --- a/src/main/java/lu/jpt/csparqlproject/rentacar/RentACarSimulation.java +++ b/src/main/java/lu/jpt/csparqlproject/rentacar/RentACarSimulation.java @@ -1,15 +1,21 @@ package lu.jpt.csparqlproject.rentacar; import java.util.ArrayList; +import java.util.Collection; import java.util.List; +import java.util.Observable; +import java.util.Observer; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import eu.larkc.csparql.cep.api.RdfQuadruple; import eu.larkc.csparql.cep.api.RdfStream; +import eu.larkc.csparql.common.RDFTable; +import eu.larkc.csparql.common.RDFTuple; import eu.larkc.csparql.common.utils.CsparqlUtils; import eu.larkc.csparql.common.utils.ReasonerChainingType; +import eu.larkc.csparql.core.engine.CsparqlEngine; import lu.jpt.csparqlproject.Main; import lu.jpt.csparqlproject.misc.QueryContainer; import lu.jpt.csparqlproject.util.WindowLoggingRdfStream; @@ -42,8 +48,10 @@ public class RentACarSimulation implements Runnable { private RdfStream carStream; private RdfStream driverStream; + private CsparqlEngine engine; - public RentACarSimulation() { + public RentACarSimulation(CsparqlEngine engine) { + this.engine = engine; this.registerOwnPrefixes(); int numberOfCars = 2; // Maximum of 10 cars are in the ABox (0-9) int numberOfCustomers = 5; // Maximum of 5 drivers are in the ABox (0-4) @@ -164,7 +172,7 @@ public class RentACarSimulation implements Runnable { /** * 1) Query to determine cars that are standing still */ - public static QueryContainer getStandingCarsStream() { + public QueryContainer getStandingCarsStream() { String query = "REGISTER STREAM getStandingCars AS " + "PREFIX rdf: " + "PREFIX f: " @@ -188,7 +196,7 @@ public class RentACarSimulation implements Runnable { /** * 1) Query to determine cars that are moving */ - public static QueryContainer getMovingCarsStream() { + public QueryContainer getMovingCarsStream() { String query = "REGISTER STREAM getMovingCars AS " + "PREFIX rdf: " + "PREFIX f: " @@ -212,7 +220,7 @@ public class RentACarSimulation implements Runnable { /** * 2) Query to determine cars that are strongly accelerating */ - public static QueryContainer getStronglyAcceleratingCarsStream() { + public QueryContainer getStronglyAcceleratingCarsStream() { String query = "REGISTER STREAM getStronglyAcceleratingCars AS " + "PREFIX rdf: " + "PREFIX f: " @@ -247,7 +255,7 @@ public class RentACarSimulation implements Runnable { /** * 2) Query to determine cars that are strongly braking */ - public static QueryContainer getStronglyBrakingCarsStream() { + public QueryContainer getStronglyBrakingCarsStream() { String query = "REGISTER STREAM getStronglyBrakingCars AS " + "PREFIX rdf: " + "PREFIX f: " @@ -283,7 +291,7 @@ public class RentACarSimulation implements Runnable { * 3) Query to determine engine wear aka higher motor rpms over time * than the engine allows (see domain knowledge) */ - public static QueryContainer getEngineWearStream() { + public QueryContainer getEngineWearStream() { String query = "REGISTER STREAM getEngineWear AS " + "PREFIX rdf: " + "PREFIX f: " @@ -319,7 +327,7 @@ public class RentACarSimulation implements Runnable { * 3) Query to transform the CarStrongBrakingEvent into a * CarBrakeWearEvent. */ - public static QueryContainer getBrakeWearStream() { + public QueryContainer getBrakeWearStream() { String query = "REGISTER STREAM getBrakeWear AS " + "PREFIX rdf: " + "PREFIX f: " @@ -341,7 +349,7 @@ public class RentACarSimulation implements Runnable { /** * 3) Query to create CarHandbrakeWearEvents when cars are moving with their handbrake engaged */ - public static QueryContainer getHandbrakeWearStream() { + public QueryContainer getHandbrakeWearStream() { String query = "REGISTER STREAM getHandbrakeWear AS " + "PREFIX rdf: " + "PREFIX f: " @@ -354,7 +362,7 @@ public class RentACarSimulation implements Runnable { + "FROM STREAM <"+RentACarSimulation.CAR_STREAM_IRI+"> [RANGE 3s STEP 1s] " + "WHERE { " + " ?e rdf:type car:CarStatusEvent . " - + " ?e car:relatedCar ?car ." + + " ?e car:relatedCar ?car . " + " ?e car:handbrakeEngaged ?handbrakeEngaged . " + " ?e car:speed ?speed . " + " FILTER(?speed > 0) " @@ -367,8 +375,12 @@ public class RentACarSimulation implements Runnable { /** * 3) Query to created CarTireWearEvents when tires run with lower pressure * than allowed in domain knowledge. + * Does not work for some weird reason. Maybe limits of the engine or i overlooked something big. + * Possible solution: Use something other than xsd:double and try again. + * Additional note: Switching to xsd:integer did NOT help. Perhaps the query is too long + * or an internal limit is reached. */ - public static QueryContainer getTireWearStream() { + public QueryContainer getTireWearStream() { String query = "REGISTER STREAM getTireWear AS " + "PREFIX rdf: " + "PREFIX f: " @@ -376,37 +388,115 @@ public class RentACarSimulation implements Runnable { + "PREFIX car: <"+RentACarSimulation.BASE_ONTOLOGY_IRI+"> " + "CONSTRUCT { " + " [] rdf:type car:CarTireWearEvent " - + " ; car:relatedCar ?car " - + " ; car:tirePressureD1 ?tpdelta1 " - + " ; car:tirePressureD2 ?tpdelta2 " - + " ; car:tirePressureD3 ?tpdelta3 " - + " ; car:tirePressureD4 ?tpdelta4 " - + " ; car:minimumTirePressure ?minTirePressure . " + + " ; car:relatedCar ?car . " + "} " + "FROM STREAM <"+RentACarSimulation.CAR_STREAM_IRI+"> [RANGE 3s STEP 1s] " + "FROM " + "WHERE { " + " ?e rdf:type car:CarStatusEvent . " + " ?e car:relatedCar ?car . " + + " ?car car:isCarModel ?carModel . " + + " ?carModel car:minimumTirePressure ?minTirePressure . " + " ?e car:tirePressure1 ?tpress1 . " + " ?e car:tirePressure2 ?tpress2 . " + " ?e car:tirePressure3 ?tpress3 . " + " ?e car:tirePressure4 ?tpress4 . " - + " ?car car:isCarModel ?carModel . " - + " ?carModel car:minimumTirePressure ?minTirePressure . " - + " BIND(?minTirePressure - ?tpress1 AS ?tpdelta1) " - + " BIND(?minTirePressure - ?tpress2 AS ?tpdelta2) " - + " BIND(?minTirePressure - ?tpress3 AS ?tpdelta3) " - + " BIND(?minTirePressure - ?tpress4 AS ?tpdelta4) " - + " FILTER(?tpdelta1 > 0) " + + " FILTER(?tpress1 < ?minTirePressure || ?tpress2 < ?minTirePressure || ?tpress3 < ?minTirePressure || ?tpress4 < ?minTirePressure) " + "}"; QueryContainer queryContainer = new QueryContainer("getTireWear", query, true); return queryContainer; } + /** + * 4) Query to observe in order to update the driver or + * a car within domain knowledge accordingly. + * This query takes note of every driver currently driving a vehicle. + */ + public QueryContainer getCarTakenEventsQuery() { + String query = "REGISTER QUERY getCarTakenEvents AS " + + "PREFIX rdf: " + + "PREFIX f: " + + "PREFIX xsd: " + + "PREFIX car: <"+RentACarSimulation.BASE_ONTOLOGY_IRI+"> " + + "SELECT ?driver ?car " + + "FROM STREAM <"+RentACarSimulation.DRIVER_STREAM_IRI+"> [RANGE 3s STEP 1s] " + + "WHERE { " + + " ?e rdf:type car:CarTakenEvent . " + + " ?e car:relatedCar ?car . " + + " ?e car:relatedUser ?driver . " + + "}"; + QueryContainer queryContainer = new QueryContainer("getCarTakenEvents", query, false); + final CsparqlEngine engine = this.engine; + queryContainer.useCustomObserver(new Observer() { + @Override + public void update(Observable o, Object arg) { + RDFTable results = (RDFTable) arg; + Collection tuples = results.getTuples(); + for(RDFTuple tuple : tuples) { + String driverUri = tuple.get(0); + String carUri = tuple.get(1); + String updateQuery = "PREFIX car: <"+RentACarSimulation.BASE_ONTOLOGY_IRI+"> " + + "INSERT DATA { " + + " GRAPH { " + + " <"+driverUri+"> car:drives <"+carUri+"> . " + + " <"+carUri+"> car:isDrivenBy <"+driverUri+"> . " + + " } " + + "}"; + RentACarSimulation.logger.debug(updateQuery); + engine.execUpdateQueryOverDatasource(updateQuery); + } + } + }); + return queryContainer; + } + + /** + * 4) Query to observe in order to update the driver or + * a car within domain knowledge accordingly. + * This query removes all relationships between a driver and a car + * when the car is being returned. + */ + public QueryContainer getCarReturnedEventsQuery() { + String query = "REGISTER QUERY getCarReturnedEvents AS " + + "PREFIX rdf: " + + "PREFIX f: " + + "PREFIX xsd: " + + "PREFIX car: <"+RentACarSimulation.BASE_ONTOLOGY_IRI+"> " + + "SELECT ?driver ?car " + + "FROM STREAM <"+RentACarSimulation.DRIVER_STREAM_IRI+"> [RANGE 3s STEP 1s] " + + "WHERE { " + + " ?e rdf:type car:CarReturnedEvent . " + + " ?e car:relatedCar ?car . " + + " ?e car:relatedUser ?driver . " + + "}"; + QueryContainer queryContainer = new QueryContainer("getCarReturnedEvents", query, false); + final CsparqlEngine engine = this.engine; + queryContainer.useCustomObserver(new Observer() { + @Override + public void update(Observable o, Object arg) { + RDFTable results = (RDFTable) arg; + Collection tuples = results.getTuples(); + for(RDFTuple tuple : tuples) { + String driverUri = tuple.get(0); + String carUri = tuple.get(1); + String updateQuery = "PREFIX car: <"+RentACarSimulation.BASE_ONTOLOGY_IRI+"> " + + "DELETE DATA { " + + " GRAPH { " + + " <"+driverUri+"> car:drives <"+carUri+"> . " + + " <"+carUri+"> car:isDrivenBy <"+driverUri+"> . " + + " } " + + "}"; + RentACarSimulation.logger.debug(updateQuery); + engine.execUpdateQueryOverDatasource(updateQuery); + } + } + }); + return queryContainer; + } + ////////////////////////////////////////////////////////////// - public static QueryContainer getEventsQuery() { + public QueryContainer getEventsQuery() { String query = "REGISTER QUERY getCarStatusEvents AS " + "PREFIX rdf: " + "PREFIX f: " @@ -433,7 +523,7 @@ public class RentACarSimulation implements Runnable { return queryContainer; } - public static QueryContainer getEventUsingBackgroundKnowledge() { + public QueryContainer getEventUsingBackgroundKnowledge() { String query = "REGISTER QUERY getEventsCombinedWithBackgroundKnowledge AS " + "PREFIX rdf: " + "PREFIX f: " @@ -455,7 +545,7 @@ public class RentACarSimulation implements Runnable { return queryContainer; } - public static QueryContainer getSpeedByCar() { + public QueryContainer getSpeedByCar() { String query = "REGISTER QUERY getSpeedByCar AS " + "PREFIX rdf: " + "PREFIX f: " @@ -473,7 +563,7 @@ public class RentACarSimulation implements Runnable { return queryContainer; } - public static QueryContainer getAverageDataByCarAsStream() { + public QueryContainer getAverageDataByCarAsStream() { String query = "REGISTER STREAM getAverageSpeedByCar AS " + "PREFIX rdf: " + "PREFIX f: " @@ -504,7 +594,7 @@ public class RentACarSimulation implements Runnable { /** * IMPORTANT NOTE: STREAM gets matched everywhere, so don't call stuff "stream"! */ - public static QueryContainer selectFromRegisteredStream() { + public QueryContainer selectFromRegisteredStream() { String query = "REGISTER Query askRegisteredStrm AS " + "PREFIX rdf: " + "PREFIX f: "