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.Iterator;
|
||||||
import java.util.LinkedList;
|
import java.util.LinkedList;
|
||||||
import java.util.Queue;
|
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
import org.apache.commons.logging.Log;
|
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.rdf.model.Statement;
|
||||||
import com.hp.hpl.jena.shared.Lock;
|
import com.hp.hpl.jena.shared.Lock;
|
||||||
import com.hp.hpl.jena.util.iterator.ClosableIterator;
|
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.dao.jena.event.EditEvent;
|
||||||
import edu.cornell.mannlib.vitro.webapp.tboxreasoner.ConfiguredReasonerListener;
|
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.ReasonerConfiguration;
|
||||||
import edu.cornell.mannlib.vitro.webapp.tboxreasoner.ReasonerStatementPattern;
|
import edu.cornell.mannlib.vitro.webapp.tboxreasoner.ReasonerStatementPattern;
|
||||||
import edu.cornell.mannlib.vitro.webapp.tboxreasoner.TBoxReasonerDriver;
|
import edu.cornell.mannlib.vitro.webapp.tboxreasoner.TBoxReasonerDriver;
|
||||||
|
@ -304,9 +300,6 @@ public class PelletListener implements TBoxReasonerDriver {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int addCount = 0;
|
|
||||||
int retractCount = 0;
|
|
||||||
|
|
||||||
// force new reasoner (disabled)
|
// force new reasoner (disabled)
|
||||||
if (false && !reasonerConfiguration.isIncrementalReasoningEnabled()) {
|
if (false && !reasonerConfiguration.isIncrementalReasoningEnabled()) {
|
||||||
Model baseModel = pelletModel.getBaseModel();
|
Model baseModel = pelletModel.getBaseModel();
|
||||||
|
@ -323,88 +316,16 @@ public class PelletListener implements TBoxReasonerDriver {
|
||||||
pelletModel.leaveCriticalSection();
|
pelletModel.leaveCriticalSection();
|
||||||
}
|
}
|
||||||
|
|
||||||
for (Iterator<ReasonerStatementPattern> patIt = irpl.iterator(); patIt.hasNext(); ) {
|
InferenceModelUpdater inferenceModelUpdater = new InferenceModelUpdater(
|
||||||
ReasonerStatementPattern pat = patIt.next();
|
pelletModel, inferenceModel, fullModel, listener);
|
||||||
log.debug("Querying for "+pat);
|
inferenceModelUpdater.update(irpl);
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
this.pelletListener.isConsistent = true;
|
this.pelletListener.isConsistent = true;
|
||||||
this.pelletListener.inErrorState = false;
|
this.pelletListener.inErrorState = false;
|
||||||
this.pelletListener.explanation = "";
|
this.pelletListener.explanation = "";
|
||||||
if (log.isDebugEnabled()) {
|
if (log.isDebugEnabled()) {
|
||||||
log.info("Added "+addCount+" statements entailed by assertions");
|
log.info("Added "+inferenceModelUpdater.getAddCount()+" statements entailed by assertions");
|
||||||
log.info("Retracted "+retractCount+" statements no longer 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");
|
log.info("Done getting new inferences: "+(System.currentTimeMillis()-startTime)/1000+" seconds");
|
||||||
}
|
}
|
||||||
} catch (InconsistentOntologyException ioe) {
|
} catch (InconsistentOntologyException ioe) {
|
||||||
|
@ -421,7 +342,6 @@ public class PelletListener implements TBoxReasonerDriver {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void getInferences() {
|
private void getInferences() {
|
||||||
|
|
|
@ -13,9 +13,14 @@ import javax.servlet.ServletContext;
|
||||||
import javax.servlet.ServletContextEvent;
|
import javax.servlet.ServletContextEvent;
|
||||||
import javax.servlet.ServletContextListener;
|
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.OntModel;
|
||||||
import com.hp.hpl.jena.ontology.OntModelSpec;
|
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.ModelFactory;
|
||||||
|
import com.hp.hpl.jena.rdf.model.Statement;
|
||||||
|
|
||||||
import edu.cornell.mannlib.vitro.webapp.application.ApplicationUtils;
|
import edu.cornell.mannlib.vitro.webapp.application.ApplicationUtils;
|
||||||
import edu.cornell.mannlib.vitro.webapp.modelaccess.ModelAccess;
|
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.
|
* KLUGE -- in production, startup_listeners shouldn't mention this.
|
||||||
*/
|
*/
|
||||||
public class TBoxReasonerSmokeTest implements ServletContextListener {
|
public class TBoxReasonerSmokeTest implements ServletContextListener {
|
||||||
|
private static final Log log = LogFactory
|
||||||
|
.getLog(TBoxReasonerSmokeTest.class);
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void contextInitialized(ServletContextEvent sce) {
|
public void contextInitialized(ServletContextEvent sce) {
|
||||||
ServletContext ctx = sce.getServletContext();
|
ServletContext ctx = sce.getServletContext();
|
||||||
|
@ -53,10 +61,45 @@ public class TBoxReasonerSmokeTest implements ServletContextListener {
|
||||||
if (savedInferencesModel.isIsomorphicWith(tboxInferencesModel)) {
|
if (savedInferencesModel.isIsomorphicWith(tboxInferencesModel)) {
|
||||||
ss.info(this, "TBox inferences matches saved.");
|
ss.info(this, "TBox inferences matches saved.");
|
||||||
} else {
|
} else {
|
||||||
|
dumpDifferences(savedInferencesModel, tboxInferencesModel);
|
||||||
ss.fatal(this, "TBox inferences does not match saved.");
|
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() {
|
private File locateSavedInferencesFile() {
|
||||||
String homeDirPath = ApplicationUtils.instance().getHomeDirectory()
|
String homeDirPath = ApplicationUtils.instance().getHomeDirectory()
|
||||||
.getPath().toString();
|
.getPath().toString();
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue