VIVO-778 Break out just the task of syncing the inference model to the reasoner model.

This commit is contained in:
Jim Blake 2014-12-01 16:52:07 -05:00
parent 21727afd13
commit d513dcf9ae
3 changed files with 189 additions and 87 deletions

View file

@ -0,0 +1,139 @@
/* $This file is distributed under the terms of the license in /doc/license.txt$ */
package edu.cornell.mannlib.vitro.webapp.dao.jena.pellet;
import java.util.LinkedList;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import com.hp.hpl.jena.ontology.OntModel;
import com.hp.hpl.jena.rdf.model.Model;
import com.hp.hpl.jena.rdf.model.ModelFactory;
import com.hp.hpl.jena.rdf.model.Statement;
import com.hp.hpl.jena.vocabulary.OWL;
import com.hp.hpl.jena.vocabulary.RDFS;
import edu.cornell.mannlib.vitro.webapp.tboxreasoner.ConfiguredReasonerListener;
import edu.cornell.mannlib.vitro.webapp.tboxreasoner.ConfiguredReasonerListener.Suspension;
import edu.cornell.mannlib.vitro.webapp.tboxreasoner.ReasonerStatementPattern;
import edu.cornell.mannlib.vitro.webapp.utils.jena.criticalsection.LockableModel;
import edu.cornell.mannlib.vitro.webapp.utils.jena.criticalsection.LockableOntModel;
import edu.cornell.mannlib.vitro.webapp.utils.jena.criticalsection.LockedModel;
import edu.cornell.mannlib.vitro.webapp.utils.jena.criticalsection.LockedOntModel;
/**
* A tool that will adjust the inferences model to match the reasoner model,
* after applying the proper filters to both.
*/
public class InferenceModelUpdater {
private static final Log log = LogFactory
.getLog(InferenceModelUpdater.class);
private final LockableOntModel lockableReasonerModel;
private final LockableModel lockableInferenceModel;
private final LockableOntModel lockableFullModel;
private final ConfiguredReasonerListener listener;
private int addCount;
private int retractCount;
public int getAddCount() {
return addCount;
}
public int getRetractCount() {
return retractCount;
}
public InferenceModelUpdater(OntModel reasonerModel, Model inferenceModel,
OntModel fullModel, ConfiguredReasonerListener listener) {
this.lockableReasonerModel = new LockableOntModel(reasonerModel);
this.lockableInferenceModel = new LockableModel(inferenceModel);
this.lockableFullModel = new LockableOntModel(fullModel);
this.listener = listener;
}
/**
* Synchronize the inferences model with the reasoner model, with these
* provisos:
*
* Statements in the reasoner model about RDFS.Resource or OWL.Nothing are
* ignored.
*
* If a statement exists anywhere in the full TBox, don't bother adding it
* to the inferences model.
*/
public void update(LinkedList<ReasonerStatementPattern> patternList) {
Model filteredReasonerModel = filterReasonerModel(patternList);
addNewInferences(filteredReasonerModel);
removeOldInferences(filterInferencesModel(patternList),
filteredReasonerModel);
log.warn("Added: " + addCount + ", Retracted: " + retractCount);
}
private Model filterReasonerModel(
LinkedList<ReasonerStatementPattern> patternList) {
Model filtered = ModelFactory.createDefaultModel();
try (LockedOntModel reasonerModel = lockableReasonerModel.read()) {
for (ReasonerStatementPattern pattern : patternList) {
filtered.add(pattern.matchStatementsFromModel(reasonerModel));
}
}
for (Statement stmt : filtered.listStatements().toList()) {
if (stmt.getObject().equals(RDFS.Resource)) {
filtered.remove(stmt);
} else if (stmt.getSubject().equals(OWL.Nothing)) {
filtered.remove(stmt);
} else if (stmt.getObject().equals(OWL.Nothing)) {
filtered.remove(stmt);
}
}
log.warn("Filtered reasoner model: " + filtered.size());
return filtered;
}
private void addNewInferences(Model filteredReasonerModel) {
for (Statement stmt : filteredReasonerModel.listStatements().toList()) {
if (!fullModelContainsStatement(stmt)) {
try (LockedModel inferenceModel = lockableInferenceModel
.write(); Suspension susp = listener.suspend()) {
inferenceModel.add(stmt);
addCount++;
}
}
}
}
private boolean fullModelContainsStatement(Statement stmt) {
try (LockedOntModel fullModel = lockableFullModel.read()) {
return fullModel.contains(stmt);
}
}
private Model filterInferencesModel(
LinkedList<ReasonerStatementPattern> patternList) {
Model filtered = ModelFactory.createDefaultModel();
try (LockedOntModel reasonerModel = lockableReasonerModel.read()) {
for (ReasonerStatementPattern pattern : patternList) {
filtered.add(pattern.matchStatementsFromModel(reasonerModel));
}
}
log.warn("Filtered inferences model: " + filtered.size());
return filtered;
}
private void removeOldInferences(Model filteredInferencesModel,
Model filteredReasonerModel) {
for (Statement stmt : filteredInferencesModel.listStatements().toList()) {
if (!filteredReasonerModel.contains(stmt)) {
try (LockedModel inferenceModel = lockableInferenceModel
.write(); Suspension susp = listener.suspend()) {
retractCount++;
inferenceModel.remove(stmt);
}
}
}
}
}

View file

@ -4,7 +4,6 @@ package edu.cornell.mannlib.vitro.webapp.dao.jena.pellet;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.Queue;
import java.util.Set;
import org.apache.commons.logging.Log;
@ -24,12 +23,9 @@ import com.hp.hpl.jena.rdf.model.ResourceFactory;
import com.hp.hpl.jena.rdf.model.Statement;
import com.hp.hpl.jena.shared.Lock;
import com.hp.hpl.jena.util.iterator.ClosableIterator;
import com.hp.hpl.jena.vocabulary.OWL;
import com.hp.hpl.jena.vocabulary.RDFS;
import edu.cornell.mannlib.vitro.webapp.dao.jena.event.EditEvent;
import edu.cornell.mannlib.vitro.webapp.tboxreasoner.ConfiguredReasonerListener;
import edu.cornell.mannlib.vitro.webapp.tboxreasoner.ConfiguredReasonerListener.Suspension;
import edu.cornell.mannlib.vitro.webapp.tboxreasoner.ReasonerConfiguration;
import edu.cornell.mannlib.vitro.webapp.tboxreasoner.ReasonerStatementPattern;
import edu.cornell.mannlib.vitro.webapp.tboxreasoner.TBoxReasonerDriver;
@ -303,10 +299,7 @@ public class PelletListener implements TBoxReasonerDriver {
deletedDataProperties.leaveCriticalSection();
}
}
int addCount = 0;
int retractCount = 0;
// force new reasoner (disabled)
if (false && !reasonerConfiguration.isIncrementalReasoningEnabled()) {
Model baseModel = pelletModel.getBaseModel();
@ -323,88 +316,16 @@ public class PelletListener implements TBoxReasonerDriver {
pelletModel.leaveCriticalSection();
}
for (Iterator<ReasonerStatementPattern> patIt = irpl.iterator(); patIt.hasNext(); ) {
ReasonerStatementPattern pat = patIt.next();
log.debug("Querying for "+pat);
Model tempModel = ModelFactory.createDefaultModel();
pelletModel.enterCriticalSection(Lock.READ);
try {
for(Statement stmt : pat.matchStatementsFromModel(pelletModel)) {
boolean reject = false;
// this next part is only needed if we're using Jena's OWL reasoner instead of actually using Pellet
try {
if ( ( ((Resource)stmt.getObject()).equals(RDFS.Resource) ) ) {
reject = true;
} else if ( ( stmt.getSubject().equals(OWL.Nothing) ) ) {
reject = true;
} else if ( ( stmt.getObject().equals(OWL.Nothing) ) ) {
reject = true;
}
} catch (Exception e) {}
if (!reject) {
tempModel.add(stmt);
boolean fullModelContainsStatement = false;
fullModel.enterCriticalSection(Lock.READ);
try {
fullModelContainsStatement = fullModel.contains(stmt);
} finally {
fullModel.leaveCriticalSection();
}
if (!fullModelContainsStatement) {
// in theory we should be able to lock only the inference model, but I'm not sure yet if Jena propagates the locking upward
fullModel.enterCriticalSection(Lock.WRITE);
try (Suspension susp = listener.suspend()) {
inferenceModel.add(stmt);
addCount++;
} finally {
fullModel.leaveCriticalSection();
}
}
}
}
} finally {
pelletModel.leaveCriticalSection();
}
// now we see what's in the inference model that isn't in the temp model and remove it
try {
Queue<Statement> localRemovalQueue = new LinkedList<Statement>();
for (Statement stmt : pat.matchStatementsFromModel(inferenceModel)) {
if (!tempModel.contains(stmt)) {
localRemovalQueue.add(stmt);
}
}
for (Iterator<Statement> i = localRemovalQueue.iterator(); i.hasNext(); ) {
fullModel.enterCriticalSection(Lock.WRITE);
try (Suspension susp = listener.suspend()) {
retractCount++;
inferenceModel.remove(i.next());
} finally {
fullModel.leaveCriticalSection();
}
}
localRemovalQueue.clear();
} catch (Exception e) {
log.error("Error getting inferences", e);
}
tempModel = null;
}
InferenceModelUpdater inferenceModelUpdater = new InferenceModelUpdater(
pelletModel, inferenceModel, fullModel, listener);
inferenceModelUpdater.update(irpl);
this.pelletListener.isConsistent = true;
this.pelletListener.inErrorState = false;
this.pelletListener.explanation = "";
if (log.isDebugEnabled()) {
log.info("Added "+addCount+" statements entailed by assertions");
log.info("Retracted "+retractCount+" statements no longer entailed by assertions");
log.info("Added "+inferenceModelUpdater.getAddCount()+" statements entailed by assertions");
log.info("Retracted "+inferenceModelUpdater.getRetractCount()+" statements no longer entailed by assertions");
log.info("Done getting new inferences: "+(System.currentTimeMillis()-startTime)/1000+" seconds");
}
} catch (InconsistentOntologyException ioe) {
@ -421,7 +342,6 @@ public class PelletListener implements TBoxReasonerDriver {
}
}
}
}
private void getInferences() {

View file

@ -13,9 +13,14 @@ import javax.servlet.ServletContext;
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import com.hp.hpl.jena.ontology.OntModel;
import com.hp.hpl.jena.ontology.OntModelSpec;
import com.hp.hpl.jena.rdf.model.Model;
import com.hp.hpl.jena.rdf.model.ModelFactory;
import com.hp.hpl.jena.rdf.model.Statement;
import edu.cornell.mannlib.vitro.webapp.application.ApplicationUtils;
import edu.cornell.mannlib.vitro.webapp.modelaccess.ModelAccess;
@ -33,6 +38,9 @@ import edu.cornell.mannlib.vitro.webapp.startup.StartupStatus;
* KLUGE -- in production, startup_listeners shouldn't mention this.
*/
public class TBoxReasonerSmokeTest implements ServletContextListener {
private static final Log log = LogFactory
.getLog(TBoxReasonerSmokeTest.class);
@Override
public void contextInitialized(ServletContextEvent sce) {
ServletContext ctx = sce.getServletContext();
@ -53,10 +61,45 @@ public class TBoxReasonerSmokeTest implements ServletContextListener {
if (savedInferencesModel.isIsomorphicWith(tboxInferencesModel)) {
ss.info(this, "TBox inferences matches saved.");
} else {
dumpDifferences(savedInferencesModel, tboxInferencesModel);
ss.fatal(this, "TBox inferences does not match saved.");
}
}
private void dumpDifferences(OntModel savedInferencesModel,
OntModel tboxInferencesModel) {
Model missingStatements = ModelFactory.createDefaultModel();
for (Statement stmt : savedInferencesModel.listStatements().toList()) {
if (!tboxInferencesModel.contains(stmt)) {
missingStatements.add(stmt);
}
}
Model extraStatements = ModelFactory.createDefaultModel();
for (Statement stmt : tboxInferencesModel.listStatements().toList()) {
if (!savedInferencesModel.contains(stmt)) {
extraStatements.add(stmt);
}
}
log.error("inferences: " + tboxInferencesModel.size() + ", saved: "
+ savedInferencesModel.size() + ", missing: "
+ missingStatements.size() + ", extra: "
+ extraStatements.size());
String missing = "";
for (Statement stmt : missingStatements.listStatements().toList()) {
missing += "\n " + stmt;
}
log.error("missing statements:" + missing);
String extras = "";
for (Statement stmt : extraStatements.listStatements().toList()) {
extras += "\n " + stmt;
}
log.error("extra statements:" + extras);
}
private File locateSavedInferencesFile() {
String homeDirPath = ApplicationUtils.instance().getHomeDirectory()
.getPath().toString();