diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/reasoner/ABoxRecomputer.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/reasoner/ABoxRecomputer.java index fbbc5702f..0c7bca4f1 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/reasoner/ABoxRecomputer.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/reasoner/ABoxRecomputer.java @@ -107,6 +107,9 @@ public class ABoxRecomputer { } } + // don't check for existing inferences in the rebuild model + private boolean DO_CHECK = true; + /* * Recompute the entire ABox inference graph. The new * inference graph is built in a separate model and @@ -132,11 +135,13 @@ public class ABoxRecomputer { log.info("Recomputing inferences for " + individuals.size() + " individuals"); + long start = System.currentTimeMillis(); + for (String individualURI : individuals) { Resource individual = ResourceFactory.createResource(individualURI); try { - addedABoxTypeAssertion(individual, inferenceRebuildModel, unknownTypes); + addedABoxTypeAssertion(individual, inferenceRebuildModel, unknownTypes, DO_CHECK); simpleReasoner.setMostSpecificTypes(individual, inferenceRebuildModel, unknownTypes); List pluginList = simpleReasoner.getPluginList(); if (pluginList.size() > 0) { @@ -165,8 +170,11 @@ public class ABoxRecomputer { } numStmts++; - if ((numStmts % 10000) == 0) { - log.info("Still computing class subsumption ABox inferences..."); + if ((numStmts % 1000) == 0) { + log.info("Still computing class subsumption ABox inferences (" + + numStmts + "/" + individuals.size() + " individuals)"); + log.info((System.currentTimeMillis() - start) / 1000 + " ms per individual"); + start = System.currentTimeMillis(); } if (stopRequested) { @@ -275,7 +283,7 @@ public class ABoxRecomputer { log.info("Finished computing sameAs ABox inferences"); try { - if (updateInferenceModel(inferenceRebuildModel)) { + if (updateInferenceModel(inferenceRebuildModel, individuals)) { log.info("a stopRequested signal was received during updateInferenceModel. Halting Processing."); return; } @@ -365,8 +373,14 @@ public class ABoxRecomputer { } } - - protected void addedABoxTypeAssertion(Resource individual, Model inferenceModel, HashSet unknownTypes) { + + protected void addedABoxTypeAssertion(Resource individual, Model inferenceModel, + HashSet unknownTypes) { + addedABoxTypeAssertion(individual, inferenceModel, unknownTypes, true); + } + + protected void addedABoxTypeAssertion(Resource individual, Model inferenceModel, + HashSet unknownTypes, boolean checkRedundancy) { StmtIterator iter = null; @@ -376,7 +390,8 @@ public class ABoxRecomputer { while (iter.hasNext()) { Statement stmt = iter.next(); - simpleReasoner.addedABoxTypeAssertion(stmt, inferenceModel, unknownTypes); + simpleReasoner.addedABoxTypeAssertion( + stmt, inferenceModel, unknownTypes, checkRedundancy); } } finally { if (iter != null) { @@ -388,125 +403,72 @@ public class ABoxRecomputer { /* * reconcile a set of inferences into the application inference model */ - protected boolean updateInferenceModel(Model inferenceRebuildModel) { + protected boolean updateInferenceModel(Model inferenceRebuildModel, + Collection individuals) { + + log.info("Updating ABox inference model"); + + // Remove everything from the current inference model that is not + // in the recomputed inference model + int num = 0; + scratchpadModel.enterCriticalSection(Lock.WRITE); + scratchpadModel.removeAll(); + Model rebuild = ModelFactory.createDefaultModel(); + Model existing = ModelFactory.createDefaultModel(); - log.info("Updating ABox inference model"); - Iterator iter = null; - - // Remove everything from the current inference model that is not - // in the recomputed inference model - int num = 0; - scratchpadModel.enterCriticalSection(Lock.WRITE); - scratchpadModel.removeAll(); - log.info("Updating ABox inference model (checking for outdated inferences)"); - try { - inferenceModel.enterCriticalSection(Lock.READ); - - try { - iter = listModelStatements(inferenceModel, JenaDataSourceSetupBase.JENA_INF_MODEL); - while (iter.hasNext()) { - Statement stmt = iter.next(); - if (!inferenceRebuildModel.contains(stmt)) { - scratchpadModel.add(stmt); - } - - num++; - if ((num % 10000) == 0) { - log.info("Still updating ABox inference model (checking for outdated inferences)..."); - } - - if (stopRequested) { - return true; - } - } - } finally { -// if (iter != null) { -// iter.close(); -// } - inferenceModel.leaveCriticalSection(); - } - - try { - iter = listModelStatements(scratchpadModel, SimpleReasonerSetup.JENA_INF_MODEL_SCRATCHPAD); - while (iter.hasNext()) { - Statement stmt = iter.next(); - - // skip statements with blank nodes to avoid excessive deletion - if (stmt.getSubject().isAnon() || stmt.getObject().isAnon()) { - continue; - } - - inferenceModel.enterCriticalSection(Lock.WRITE); - try { - inferenceModel.remove(stmt); - } finally { - inferenceModel.leaveCriticalSection(); - } - } - } finally { -// if (iter != null) { -// iter.close(); -// } - } - - // Add everything from the recomputed inference model that is not already - // in the current inference model to the current inference model. - try { - scratchpadModel.removeAll(); - log.info("Updating ABox inference model (adding any new inferences)"); - iter = listModelStatements(inferenceRebuildModel, SimpleReasonerSetup.JENA_INF_MODEL_REBUILD); - - while (iter.hasNext()) { - Statement stmt = iter.next(); - - inferenceModel.enterCriticalSection(Lock.READ); - try { - if (!inferenceModel.contains(stmt)) { - scratchpadModel.add(stmt); - } - } finally { - inferenceModel.leaveCriticalSection(); - } - - num++; - if ((num % 10000) == 0) { - log.info("Still updating ABox inference model (adding any new inferences)..."); - } - - if (stopRequested) { - return true; - } - } - } finally { -// if (iter != null) { -// iter.close(); -// } - } - - iter = listModelStatements(scratchpadModel, SimpleReasonerSetup.JENA_INF_MODEL_SCRATCHPAD); - try { - while (iter.hasNext()) { - Statement stmt = iter.next(); - - inferenceModel.enterCriticalSection(Lock.WRITE); - try { - inferenceModel.add(stmt); - } finally { - inferenceModel.leaveCriticalSection(); - } - } - } finally { -// if (iter != null) { -// iter.close(); -// } - } - } finally { - scratchpadModel.removeAll(); - scratchpadModel.leaveCriticalSection(); - } - - log.info("ABox inference model updated"); - return false; + long start = System.currentTimeMillis(); + + for (String individualURI : individuals) { + rebuild.removeAll(); + existing.removeAll(); + Resource subjInd = ResourceFactory.createResource(individualURI); + inferenceModel.enterCriticalSection(Lock.READ); + try { + existing.add(inferenceModel.listStatements(subjInd, null, (RDFNode) null)); + } finally { + inferenceModel.leaveCriticalSection(); + } + inferenceRebuildModel.enterCriticalSection(Lock.READ); + try { + rebuild.add(inferenceRebuildModel.listStatements(subjInd, null, (RDFNode) null)); + } finally { + inferenceRebuildModel.leaveCriticalSection(); + } + + Model retractions = existing.difference(rebuild); + Model additions = rebuild.difference(existing); + + inferenceModel.enterCriticalSection(Lock.WRITE); + try { + inferenceModel.remove(retractions); + inferenceModel.add(additions); + } finally { + inferenceModel.leaveCriticalSection(); + } + + inferenceRebuildModel.enterCriticalSection(Lock.WRITE); + try { + inferenceRebuildModel.remove(rebuild); + } finally { + inferenceRebuildModel.leaveCriticalSection(); + } + + num++; + if ((num % 1000) == 0) { + log.info("Still updating ABox inference model (" + + + num + "/" + individuals.size() + " individuals)"); + log.info((System.currentTimeMillis() - start) / 1000 + " ms per individual"); + start = System.currentTimeMillis(); + } + + if (stopRequested) { + return true; + } + + } + + log.info("ABox inference model updated"); + return false; } private Iterator listModelStatements(Model model, String graphURI) { diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/reasoner/ReasonerPlugin.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/reasoner/ReasonerPlugin.java index aa3ce9689..5b38ef81e 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/reasoner/ReasonerPlugin.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/reasoner/ReasonerPlugin.java @@ -12,6 +12,8 @@ public interface ReasonerPlugin { public boolean isInterestedInRemovedStatement(Statement stmt); + public boolean isConfigurationOnlyPlugin(); + public void addedABoxStatement(Statement stmt, Model aboxAssertionsModel, Model aboxInferencesModel, diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/reasoner/SimpleReasoner.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/reasoner/SimpleReasoner.java index 4374f0b58..0f40e4721 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/reasoner/SimpleReasoner.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/reasoner/SimpleReasoner.java @@ -161,6 +161,10 @@ public class SimpleReasoner extends StatementListener { public void setSameAsEnabled( boolean tf){ this.doSameAs = tf; } + + public boolean getSameAsEnabled() { + return this.doSameAs; + } /* * Performs incremental ABox reasoning based @@ -342,6 +346,12 @@ public class SimpleReasoner extends StatementListener { public void removedTBoxStatement(Statement stmt) { changedTBoxStatement(stmt, false); } + + protected void addedABoxTypeAssertion(Statement stmt, + Model inferenceModel, + HashSet unknownTypes) { + addedABoxTypeAssertion(stmt, inferenceModel, unknownTypes, true); + } /** * Performs incremental reasoning based on a new type assertion @@ -353,7 +363,8 @@ public class SimpleReasoner extends StatementListener { */ protected void addedABoxTypeAssertion(Statement stmt, Model inferenceModel, - HashSet unknownTypes) { + HashSet unknownTypes, + boolean checkRedundancy) { tboxModel.enterCriticalSection(Lock.READ); try { @@ -379,7 +390,7 @@ public class SimpleReasoner extends StatementListener { Statement infStmt = ResourceFactory.createStatement(stmt.getSubject(), RDF.type, parentClass); - addInference(infStmt,inferenceModel,true); + addInference(infStmt, inferenceModel, true, checkRedundancy); } } } else { @@ -1189,13 +1200,20 @@ public class SimpleReasoner extends StatementListener { addInference(infStmt,inferenceModel,true); } - protected void addInference(Statement infStmt, Model inferenceModel, boolean handleSameAs) { + protected void addInference(Statement infStmt, Model inferenceModel, + boolean handleSameAs) { + addInference(infStmt, inferenceModel, handleSameAs, true); + } + + protected void addInference(Statement infStmt, Model inferenceModel, + boolean handleSameAs, boolean checkRedundancy) { aboxModel.enterCriticalSection(Lock.READ); try { inferenceModel.enterCriticalSection(Lock.WRITE); try { - if (!inferenceModel.contains(infStmt) && !aboxModel.contains(infStmt)) { + if (!checkRedundancy + || (!inferenceModel.contains(infStmt) && !aboxModel.contains(infStmt))) { inferenceModel.add(infStmt); } @@ -1730,9 +1748,7 @@ public class SimpleReasoner extends StatementListener { log.info("ending DeltaComputer.run. batchMode = " + batchMode); } - } - - + } /** * Utility method for logging diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/reasoner/plugin/DisableSameAs.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/reasoner/plugin/DisableSameAs.java index 009f0b409..1452f55cf 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/reasoner/plugin/DisableSameAs.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/reasoner/plugin/DisableSameAs.java @@ -15,7 +15,7 @@ import edu.cornell.mannlib.vitro.webapp.reasoner.SimpleReasoner; /** * Disables sameAs in associated SimpleReasoner. */ -public abstract class DisableSameAs implements ReasonerPlugin { +public class DisableSameAs implements ReasonerPlugin { private static final Log log = LogFactory.getLog(DisableSameAs.class); @@ -27,6 +27,10 @@ public abstract class DisableSameAs implements ReasonerPlugin { log.info("owl:sameAs disabled in SimpleReasoner."); } + public boolean isConfigurationOnlyPlugin() { + return true; + } + public SimpleReasoner getSimpleReasoner() { return this.simpleReasoner; } diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/reasoner/plugin/SimpleBridgingRule.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/reasoner/plugin/SimpleBridgingRule.java index 18179e0c4..6ffb1853e 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/reasoner/plugin/SimpleBridgingRule.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/reasoner/plugin/SimpleBridgingRule.java @@ -62,6 +62,10 @@ public abstract class SimpleBridgingRule implements ReasonerPlugin { } + public boolean isConfigurationOnlyPlugin() { + return false; + } + public boolean isInterestedInAddedStatement(Statement stmt) { return isRelevantPredicate(stmt); } diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/reasoner/plugin/SimplePropertyAndTypeRule.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/reasoner/plugin/SimplePropertyAndTypeRule.java index 0518bf617..b8431a281 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/reasoner/plugin/SimplePropertyAndTypeRule.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/reasoner/plugin/SimplePropertyAndTypeRule.java @@ -36,6 +36,10 @@ public abstract class SimplePropertyAndTypeRule implements ReasonerPlugin { INFERRED_PROP = ResourceFactory.createProperty(inferredProp); } + public boolean isConfigurationOnlyPlugin() { + return false; + } + public boolean isInterestedInAddedStatement(Statement stmt) { return (RDF.type.equals(stmt.getPredicate()) || isRelevantPredicate(stmt)); } diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/servlet/setup/SimpleReasonerSetup.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/servlet/setup/SimpleReasonerSetup.java index 6d99d4c52..78470712f 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/servlet/setup/SimpleReasonerSetup.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/servlet/setup/SimpleReasonerSetup.java @@ -104,7 +104,10 @@ public class SimpleReasonerSetup implements ServletContextListener { ReasonerPlugin plugin = (ReasonerPlugin) Class.forName( classname).getConstructors()[0].newInstance(); plugin.setSimpleReasoner(simpleReasoner); - pluginList.add(plugin); + if (!plugin.isConfigurationOnlyPlugin()) { + pluginList.add(plugin); + log.info("adding reasoner plugin " + plugin.getClass().getName()); + } } catch(Throwable t) { ss.info(this, "Could not instantiate reasoner plugin " + classname); } diff --git a/webapp/test/edu/cornell/mannlib/vitro/webapp/reasoner/SimpleReasonerInversePropertyTest.java b/webapp/test/edu/cornell/mannlib/vitro/webapp/reasoner/SimpleReasonerInversePropertyTest.java index 0003d576a..12f157725 100644 --- a/webapp/test/edu/cornell/mannlib/vitro/webapp/reasoner/SimpleReasonerInversePropertyTest.java +++ b/webapp/test/edu/cornell/mannlib/vitro/webapp/reasoner/SimpleReasonerInversePropertyTest.java @@ -14,6 +14,7 @@ import com.hp.hpl.jena.ontology.OntProperty; import com.hp.hpl.jena.rdf.model.Model; import com.hp.hpl.jena.rdf.model.ModelFactory; import com.hp.hpl.jena.rdf.model.Resource; +import com.hp.hpl.jena.vocabulary.OWL; import edu.cornell.mannlib.vitro.testing.AbstractTestClass; import edu.cornell.mannlib.vitro.webapp.utils.threads.VitroBackgroundThread; @@ -431,10 +432,10 @@ public class SimpleReasonerInversePropertyTest extends AbstractTestClass { tBox.register(simpleReasonerTBoxListener); // add abox data - Resource a = aBox.createResource("http://test.vivo/a"); - Resource b = aBox.createResource("http://test.vivo/b"); - Resource c = aBox.createResource("http://test.vivo/c"); - Resource d = aBox.createResource("http://test.vivo/d"); + Resource a = aBox.createIndividual("http://test.vivo/a", OWL.Thing); + Resource b = aBox.createIndividual("http://test.vivo/b", OWL.Thing); + Resource c = aBox.createIndividual("http://test.vivo/c", OWL.Thing); + Resource d = aBox.createIndividual("http://test.vivo/d", OWL.Thing); aBox.add(a,P,b); aBox.add(c,P,d); @@ -496,8 +497,8 @@ public class SimpleReasonerInversePropertyTest extends AbstractTestClass { tBox.register(simpleReasonerTBoxListener); // add statements to the abox and verify inference - Resource c = aBox.createResource("http://test.vivo/c"); - Resource d = aBox.createResource("http://test.vivo/d"); + Resource c = aBox.createIndividual("http://test.vivo/c", OWL.Thing); + Resource d = aBox.createIndividual("http://test.vivo/d", OWL.Thing); aBox.add(c,P,d); Assert.assertTrue(inf.contains(d,Q,c)); @@ -555,10 +556,10 @@ public class SimpleReasonerInversePropertyTest extends AbstractTestClass { aBox.register(simpleReasoner); // abox statements - Resource a = aBox.createResource("http://test.vivo/a"); - Resource b = aBox.createResource("http://test.vivo/b"); - Resource c = aBox.createResource("http://test.vivo/c"); - Resource d = aBox.createResource("http://test.vivo/d"); + Resource a = aBox.createIndividual("http://test.vivo/a", OWL.Thing); + Resource b = aBox.createIndividual("http://test.vivo/b", OWL.Thing); + Resource c = aBox.createIndividual("http://test.vivo/c", OWL.Thing); + Resource d = aBox.createIndividual("http://test.vivo/d", OWL.Thing); aBox.add(a,P,b); aBox.add(c,X,d); diff --git a/webapp/test/edu/cornell/mannlib/vitro/webapp/reasoner/SimpleReasonerSameAsTest.java b/webapp/test/edu/cornell/mannlib/vitro/webapp/reasoner/SimpleReasonerSameAsTest.java index c3b485803..81b7242f5 100644 --- a/webapp/test/edu/cornell/mannlib/vitro/webapp/reasoner/SimpleReasonerSameAsTest.java +++ b/webapp/test/edu/cornell/mannlib/vitro/webapp/reasoner/SimpleReasonerSameAsTest.java @@ -782,10 +782,10 @@ public class SimpleReasonerSameAsTest extends AbstractTestClass { aBox.register(simpleReasoner); // Individuals a, b, c and d - Resource a = aBox.createResource("http://test.vivo/a"); - Resource b = aBox.createResource("http://test.vivo/b"); - Resource c = aBox.createResource("http://test.vivo/c"); - Resource d = aBox.createResource("http://test.vivo/d"); + Resource a = aBox.createIndividual("http://test.vivo/a", OWL.Thing); + Resource b = aBox.createIndividual("http://test.vivo/b", OWL.Thing); + Resource c = aBox.createIndividual("http://test.vivo/c", OWL.Thing); + Resource d = aBox.createIndividual("http://test.vivo/d", OWL.Thing); aBox.add(a,P,c); aBox.add(a,S,literal1);