NIHVIVO-2039 improvement to population of applicable object properties
This commit is contained in:
parent
3853e34f56
commit
298ed7b79f
2 changed files with 220 additions and 48 deletions
|
@ -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();
|
||||||
|
|
||||||
|
@ -147,51 +173,130 @@ public class PropertyInstanceDaoJena extends JenaBaseDao implements
|
||||||
}
|
}
|
||||||
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>();
|
||||||
|
relatedClasses.addAll(ontClass.listEquivalentClasses().toList());
|
||||||
|
relatedClasses.addAll(ontClass.listSuperClasses().toList());
|
||||||
|
for (OntClass relatedClass : relatedClasses) {
|
||||||
|
// find properties in restrictions
|
||||||
|
if (relatedClass.isRestriction()) {
|
||||||
// TODO: check if restriction is something like
|
// TODO: check if restriction is something like
|
||||||
// maxCardinality 0 or allValuesFrom owl:Nothing,
|
// maxCardinality 0 or allValuesFrom owl:Nothing,
|
||||||
// in which case the property is NOT applicable!
|
// in which case the property is NOT applicable!
|
||||||
Restriction rest = (Restriction) ontClass.as(Restriction.class);
|
Restriction rest = (Restriction) relatedClass.as(Restriction.class);
|
||||||
OntProperty onProperty = rest.getOnProperty();
|
OntProperty onProperty = rest.getOnProperty();
|
||||||
if (onProperty != null && onProperty.canAs(ObjectProperty.class)) {
|
if (onProperty != null && onProperty.canAs(ObjectProperty.class)) {
|
||||||
applicableProperties.add((ObjectProperty)onProperty.as(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();
|
||||||
}
|
}
|
||||||
|
|
|
@ -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"));
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue