VIVO-778 Break out just the task of syncing the inference model to the reasoner model.
This commit is contained in:
parent
21727afd13
commit
d513dcf9ae
3 changed files with 189 additions and 87 deletions
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -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() {
|
||||
|
|
|
@ -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();
|
||||
|
|
Loading…
Add table
Reference in a new issue