NIHVIVO-2039 improvement to population of applicable object properties

This commit is contained in:
bjl23 2011-02-04 20:39:12 +00:00
parent 3853e34f56
commit 298ed7b79f
2 changed files with 220 additions and 48 deletions

View file

@ -14,17 +14,22 @@ import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Set; import java.util.Set;
import com.hp.hpl.jena.ontology.AllValuesFromRestriction;
import com.hp.hpl.jena.ontology.ObjectProperty; import com.hp.hpl.jena.ontology.ObjectProperty;
import com.hp.hpl.jena.ontology.OntClass; import com.hp.hpl.jena.ontology.OntClass;
import com.hp.hpl.jena.ontology.OntModel; import com.hp.hpl.jena.ontology.OntModel;
import com.hp.hpl.jena.ontology.OntProperty; import com.hp.hpl.jena.ontology.OntProperty;
import com.hp.hpl.jena.ontology.Restriction; import com.hp.hpl.jena.ontology.Restriction;
import com.hp.hpl.jena.ontology.SomeValuesFromRestriction;
import com.hp.hpl.jena.rdf.model.Property; import com.hp.hpl.jena.rdf.model.Property;
import com.hp.hpl.jena.rdf.model.ResIterator;
import com.hp.hpl.jena.rdf.model.Resource; import com.hp.hpl.jena.rdf.model.Resource;
import com.hp.hpl.jena.rdf.model.ResourceFactory; 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.rdf.model.StmtIterator;
import com.hp.hpl.jena.shared.Lock; import com.hp.hpl.jena.shared.Lock;
import com.hp.hpl.jena.vocabulary.OWL; import com.hp.hpl.jena.vocabulary.OWL;
import com.hp.hpl.jena.vocabulary.RDFS;
import edu.cornell.mannlib.vitro.webapp.beans.Individual; import edu.cornell.mannlib.vitro.webapp.beans.Individual;
import edu.cornell.mannlib.vitro.webapp.beans.ObjectPropertyStatement; import edu.cornell.mannlib.vitro.webapp.beans.ObjectPropertyStatement;
@ -95,23 +100,40 @@ public class PropertyInstanceDaoJena extends JenaBaseDao implements
public Collection<PropertyInstance> getAllPossiblePropInstForIndividual(String individualURI) { public Collection<PropertyInstance> getAllPossiblePropInstForIndividual(String individualURI) {
Individual ind = getWebappDaoFactory().getIndividualDao().getIndividualByURI(individualURI); Individual ind = getWebappDaoFactory().getIndividualDao().getIndividualByURI(individualURI);
Map<String, PropertyInstance> propURI2propInst = new HashMap<String, PropertyInstance>(); VClassDao vcDao = getWebappDaoFactory().getVClassDao();
List<VClass> allTypes = ind.getVClasses(false); // include indirect types List<VClass> allTypes = ind.getVClasses(false); // include indirect types
Collections.sort(allTypes, new VClassHierarchyRanker(this.getWebappDaoFactory().getVClassDao()));
for (VClass currClass : allTypes) { Set<String> allSuperclassURIs = new HashSet<String>();
Collection<PropertyInstance> propInstsForClass = getAllPropInstByVClass(currClass.getURI());
for (PropertyInstance propInst : propInstsForClass) { for (VClass type : allTypes) {
if (propURI2propInst.get(propInst.getPropertyURI()) == null) { String classURI = type.getURI();
propURI2propInst.put(propInst.getPropertyURI(), propInst); if (classURI != null) {
} allSuperclassURIs.add(type.getURI());
} }
for (String equivURI : vcDao.getEquivalentClassURIs(classURI)) {
allSuperclassURIs.add(equivURI);
allSuperclassURIs.addAll(vcDao.getAllSuperClassURIs(equivURI));
}
allSuperclassURIs.addAll(vcDao.getAllSuperClassURIs(classURI));
}
List<VClass> vclasses = new ArrayList<VClass>();
for(String vclassURI : allSuperclassURIs) {
VClass vclass = vcDao.getVClassByURI(vclassURI);
if (vclass != null) {
vclasses.add(vclass);
}
}
Collection<PropertyInstance> piList = getAllPropInstByVClasses(vclasses);
for (PropertyInstance pi : piList) {
pi.setDomainClassURI(ind.getVClassURI());
// TODO: improve. This is so the DWR property editing passes the
// individual's VClass to get the right restrictions
} }
for (PropertyInstance pi : propURI2propInst.values()) {
pi.setDomainClassURI(ind.getVClassURI()); // TODO: improve. This is so the DWR property editing passes the individual's VClass to get the right restrictions
}
List<PropertyInstance> piList = new ArrayList<PropertyInstance>();
piList.addAll(propURI2propInst.values());
Collections.sort(piList, new PropInstSorter());
return piList; return piList;
} }
@ -126,15 +148,19 @@ public class PropertyInstanceDaoJena extends JenaBaseDao implements
public int compare(VClass vc1, VClass vc2) { public int compare(VClass vc1, VClass vc2) {
if (vcDao.isSubClassOf(vc1, vc2)) { if (vcDao.isSubClassOf(vc1, vc2)) {
return -1; return -1;
} else return 0; } else if (vcDao.isSubClassOf(vc2, vc1)) {
return 1;
} else {
return 0;
}
} }
} }
public Collection<PropertyInstance> getAllPropInstByVClass(String classURI) { public Collection<PropertyInstance> getAllPropInstByVClass(String classURI) {
if (classURI==null || classURI.length()<1) { if (classURI==null || classURI.length()<1) {
return null; return null;
} }
List<PropertyInstance> propInsts = new ArrayList();
VClassDao vcDao = getWebappDaoFactory().getVClassDao(); VClassDao vcDao = getWebappDaoFactory().getVClassDao();
@ -142,56 +168,135 @@ public class PropertyInstanceDaoJena extends JenaBaseDao implements
allSuperclassURIs.add(classURI); allSuperclassURIs.add(classURI);
for (String equivURI : vcDao.getEquivalentClassURIs(classURI)) { for (String equivURI : vcDao.getEquivalentClassURIs(classURI)) {
allSuperclassURIs.add(equivURI); allSuperclassURIs.add(equivURI);
allSuperclassURIs.addAll(vcDao.getAllSuperClassURIs(equivURI)); allSuperclassURIs.addAll(vcDao.getAllSuperClassURIs(equivURI));
} }
allSuperclassURIs.addAll(vcDao.getAllSuperClassURIs(classURI)); allSuperclassURIs.addAll(vcDao.getAllSuperClassURIs(classURI));
List<VClass> vclasses = new ArrayList<VClass>();
for(String vclassURI : allSuperclassURIs) {
VClass vclass = vcDao.getVClassByURI(vclassURI);
if (vclass != null) {
vclasses.add(vclass);
}
}
return getAllPropInstByVClasses(vclasses);
}
private void updatePropertyRangeMap(Map<String, Resource[]> map,
String propURI,
Resource[] ranges) {
Resource[] existingRanges = map.get(propURI);
if (existingRanges == null) {
map.put(propURI, ranges);
} else if (existingRanges[0] == null && existingRanges[1] != null) {
existingRanges[0] = ranges[0];
map.put(propURI, existingRanges);
} else if (existingRanges[0] != null && existingRanges[1] == null) {
existingRanges[1] = ranges[1];
map.put(propURI, existingRanges);
}
}
public Collection<PropertyInstance> getAllPropInstByVClasses(List<VClass> vclasses) {
List<PropertyInstance> propInsts = new ArrayList<PropertyInstance>();
if(vclasses == null || vclasses.isEmpty()) {
return propInsts;
}
Collections.sort(vclasses, new VClassHierarchyRanker(this.getWebappDaoFactory().getVClassDao()));
OntModel ontModel = getOntModelSelector().getTBoxModel(); OntModel ontModel = getOntModelSelector().getTBoxModel();
try { try {
ontModel.enterCriticalSection(Lock.READ); ontModel.enterCriticalSection(Lock.READ);
Set<ObjectProperty> applicableProperties = new HashSet<ObjectProperty>(); // map object property URI to an array of two resources:
// the first is the "allValuesFrom" resource and the second is
// "someValuesFrom"
Map<String, Resource[]> applicableProperties =
new HashMap<String, Resource[]>();
try { try {
for (String VClassURI : allSuperclassURIs) { for (VClass vclass : vclasses) {
if (vclass.isAnonymous()) {
continue;
}
String VClassURI = vclass.getURI();
OntClass ontClass = getOntClass(ontModel,VClassURI); OntClass ontClass = getOntClass(ontModel,VClassURI);
if (ontClass != null) { if (ontClass != null) {
if (ontClass.isRestriction()) { List<OntClass> relatedClasses = new ArrayList<OntClass>();
// TODO: check if restriction is something like relatedClasses.addAll(ontClass.listEquivalentClasses().toList());
// maxCardinality 0 or allValuesFrom owl:Nothing, relatedClasses.addAll(ontClass.listSuperClasses().toList());
// in which case the property is NOT applicable! for (OntClass relatedClass : relatedClasses) {
Restriction rest = (Restriction) ontClass.as(Restriction.class); // find properties in restrictions
OntProperty onProperty = rest.getOnProperty(); if (relatedClass.isRestriction()) {
if (onProperty != null && onProperty.canAs(ObjectProperty.class)) { // TODO: check if restriction is something like
applicableProperties.add((ObjectProperty)onProperty.as(ObjectProperty.class)); // maxCardinality 0 or allValuesFrom owl:Nothing,
} // in which case the property is NOT applicable!
Restriction rest = (Restriction) relatedClass.as(Restriction.class);
OntProperty onProperty = rest.getOnProperty();
if (onProperty != null && onProperty.canAs(ObjectProperty.class)) {
Resource[] ranges = new Resource[2];
if (rest.isAllValuesFromRestriction()) {
ranges[0] = (rest.asAllValuesFromRestriction()).getAllValuesFrom();
} else if (rest.isSomeValuesFromRestriction()) {
ranges[1] = (rest.asSomeValuesFromRestriction()).getSomeValuesFrom();
}
updatePropertyRangeMap(applicableProperties, onProperty.getURI(), ranges);
}
}
}
// find properties with class in domain
ResIterator pit = ontModel.listSubjectsWithProperty(
RDFS.domain, ontClass);
while (pit.hasNext()) {
Resource prop = pit.nextResource();
if (prop.getNameSpace() != null
&& !NONUSER_NAMESPACES.contains(
prop.getNameSpace()) ) {
StmtIterator rangeSit = prop.listProperties(
RDFS.range);
Resource rangeRes = null;
while (rangeSit.hasNext()) {
Statement s = rangeSit.nextStatement();
if (s.getObject().isURIResource()) {
rangeRes = (Resource) s.getObject();
}
}
Resource[] ranges = new Resource[2];
ranges[0] = rangeRes;
updatePropertyRangeMap(
applicableProperties, prop.getURI(), ranges);
}
} }
} }
} }
} catch (Exception e) { } catch (Exception e) {
log.error("Unable to get applicable properties for " + classURI log.error("Unable to get applicable properties " +
+ " by examining property restrictions", e); "by examining property restrictions and domains", e);
} }
HashSet allSuperclassURIset = new HashSet(allSuperclassURIs); // make the PropertyInstance objects
Iterator ops = ontModel.listObjectProperties(); for (String propertyURI : applicableProperties.keySet()) {
while (ops.hasNext()) { ObjectProperty op = ontModel.getObjectProperty(propertyURI);
ObjectProperty op = (ObjectProperty) ops.next(); if (op == null) {
if (op.getNameSpace() != null && !NONUSER_NAMESPACES.contains(op.getNameSpace()) ) { continue;
Resource domainRes = op.getDomain(); }
if (domainRes != null && allSuperclassURIset.contains(getURIStr(domainRes))) {
applicableProperties.add(op);
}
}
}
for (Iterator<ObjectProperty> appPropIt = applicableProperties.iterator(); appPropIt.hasNext();) {
ObjectProperty op = appPropIt.next();
String domainURIStr = getURIStr(op.getDomain()); String domainURIStr = getURIStr(op.getDomain());
Resource rangeRes = op.getRange(); Resource[] foundRanges = applicableProperties.get(propertyURI);
Resource rangeRes = (foundRanges[0] != null)
? foundRanges[0]
: (op.getRange() == null && foundRanges[1] != null)
? foundRanges[1]
: op.getRange();
PropertyInstance pi = new PropertyInstance(); PropertyInstance pi = new PropertyInstance();
if (rangeRes != null) { if (rangeRes != null) {
String rangeClassURI; String rangeClassURI;
@ -220,7 +325,6 @@ public class PropertyInstanceDaoJena extends JenaBaseDao implements
pi.setDomainPublic(getLabelOrId(op)); pi.setDomainPublic(getLabelOrId(op));
propInsts.add(pi); propInsts.add(pi);
} }
} finally { } finally {
ontModel.leaveCriticalSection(); ontModel.leaveCriticalSection();
} }

View file

@ -3,14 +3,20 @@
package edu.cornell.mannlib.vitro.webapp.dao.jena; package edu.cornell.mannlib.vitro.webapp.dao.jena;
import java.io.StringReader; import java.io.StringReader;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import junit.framework.Assert; import junit.framework.Assert;
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.rdf.model.Model; 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.vocabulary.XSD; import com.hp.hpl.jena.vocabulary.XSD;
import edu.cornell.mannlib.vitro.webapp.beans.PropertyInstance;
import edu.cornell.mannlib.vitro.webapp.dao.VitroVocabulary; import edu.cornell.mannlib.vitro.webapp.dao.VitroVocabulary;
import edu.cornell.mannlib.vitro.webapp.dao.WebappDaoFactory; import edu.cornell.mannlib.vitro.webapp.dao.WebappDaoFactory;
@ -135,4 +141,66 @@ public class PropertyInstanceDaoJenaTest {
void wipeOutModTime(Model model){ void wipeOutModTime(Model model){
model.removeAll(null, model.createProperty(VitroVocabulary.MODTIME), null); model.removeAll(null, model.createProperty(VitroVocabulary.MODTIME), null);
} }
@org.junit.Test
public void testGetAllPossiblePropInstForIndividual() {
String n3 = prefixesN3 +
"ex:hasMold a owl:ObjectProperty . \n" +
"ex:hasSpore a owl:ObjectProperty . \n" +
"ex:hasFungus a owl:ObjectProperty . \n" +
"ex:redHerring a owl:ObjectProperty . \n" +
"ex:Person a owl:Class . \n" +
"ex:Agent a owl:Class . \n" +
"ex:Mold a owl:Class . \n" +
"ex:Spore a owl:Class . \n" +
"ex:Fungus a owl:Class . \n" +
"ex:Organism a owl:Class . \n" +
"ex:Mold rdfs:subClassOf ex:Organism . \n" +
"ex:Spore rdfs:subClassOf ex:Organism . \n" +
"ex:Fungus rdfs:subClassOf ex:Organism . \n" +
"ex:Person rdfs:subClassOf ex:Agent . \n" +
"ex:hasFungus rdfs:range ex:Fungus . \n" +
"ex:hasFungus rdfs:domain ex:Agent . \n" +
"ex:Agent rdfs:subClassOf [ a owl:Restriction ; \n" +
"owl:onProperty ex:hasMold ; \n" +
"owl:allValuesFrom ex:Organism ] . \n" +
"ex:Person rdfs:subClassOf [ a owl:Restriction ; \n" +
"owl:onProperty ex:hasMold ; \n" +
"owl:allValuesFrom ex:Mold ] . \n" +
"ex:Agent rdfs:subClassOf [ a owl:Restriction ; \n" +
"owl:onProperty ex:hasSpore ; \n" +
"owl:allValuesFrom ex:Organism ] . \n" +
"ex:Person rdfs:subClassOf [ a owl:Restriction ; \n" +
"owl:onProperty ex:hasSpore ; \n" +
"owl:someValuesFrom ex:Spore ] . \n" +
"ex:bob a ex:Person ; a ex:Agent . \n";
// The applicable properties for bob should be:
// 1. hasMold (values from Mold)
// 2. hasSpore (values from Organism)
// 3. hasFungus (values from Fungus)
OntModel ontModel = (ModelFactory.createOntologyModel(OntModelSpec.OWL_MEM));
ontModel.read(new StringReader(n3), null, "N3");
WebappDaoFactory wadf = new WebappDaoFactoryJena(ontModel);
Assert.assertEquals(4, wadf.getObjectPropertyDao().getAllObjectProperties().size());
Assert.assertEquals(6, wadf.getVClassDao().getAllVclasses().size());
Assert.assertNotNull(wadf.getIndividualDao().getIndividualByURI("http://example.com/bob"));
Collection<PropertyInstance> pinsts = wadf.getPropertyInstanceDao()
.getAllPossiblePropInstForIndividual("http://example.com/bob");
Assert.assertEquals(3, pinsts.size());
Map<String, String> propToRange = new HashMap<String,String>();
for (PropertyInstance pi : pinsts) {
propToRange.put(pi.getPropertyURI(), pi.getRangeClassURI());
}
Assert.assertEquals("http://example.com/Mold", propToRange.get("http://example.com/hasMold"));
Assert.assertEquals("http://example.com/Organism", propToRange.get("http://example.com/hasSpore"));
Assert.assertEquals("http://example.com/Fungus", propToRange.get("http://example.com/hasFungus"));
}
} }