VIVO-946 Add labels of objects across Role nodes.

This commit is contained in:
j2blake 2015-02-27 15:41:41 -05:00
parent 4e6ae2daec
commit 6166b48357
3 changed files with 103 additions and 33 deletions

View file

@ -15,10 +15,30 @@
# ------------------------------------ # ------------------------------------
:extension_forContextNodes :extension_forContextNodes_1
a <java:edu.cornell.mannlib.vitro.webapp.searchindex.indexing.IndexingUriFinder> , a <java:edu.cornell.mannlib.vitro.webapp.searchindex.indexing.IndexingUriFinder> ,
<java:edu.cornell.mannlib.vitro.webapp.searchindex.documentBuilding.DocumentModifier> , <java:edu.cornell.mannlib.vitro.webapp.searchindex.documentBuilding.DocumentModifier> ,
<java:edu.cornell.mannlib.vitro.webapp.searchindex.extensions.LabelsAcrossContextNodes> . <java:edu.cornell.mannlib.vitro.webapp.searchindex.extensions.LabelsAcrossContextNodes> ;
rdfs:label "Labels across relatedBy/relates" ;
:hasIncomingProperty "http://vivoweb.org/ontology/core#relatedBy" ;
:hasOutgoingProperty "http://vivoweb.org/ontology/core#relates" .
:extension_forContextNodes_2
a <java:edu.cornell.mannlib.vitro.webapp.searchindex.indexing.IndexingUriFinder> ,
<java:edu.cornell.mannlib.vitro.webapp.searchindex.documentBuilding.DocumentModifier> ,
<java:edu.cornell.mannlib.vitro.webapp.searchindex.extensions.LabelsAcrossContextNodes> ;
rdfs:label "Labels across bearerOf/contributesTo" ;
:hasIncomingProperty "http://purl.obolibrary.org/obo/RO_0000053" ;
:hasOutgoingProperty "http://vivoweb.org/ontology/core#roleContributesTo" .
:extension_forContextNodes_3
a <java:edu.cornell.mannlib.vitro.webapp.searchindex.indexing.IndexingUriFinder> ,
<java:edu.cornell.mannlib.vitro.webapp.searchindex.documentBuilding.DocumentModifier> ,
<java:edu.cornell.mannlib.vitro.webapp.searchindex.extensions.LabelsAcrossContextNodes> ;
rdfs:label "Labels across contributor/inheresIn" ;
:hasIncomingProperty "http://vivoweb.org/ontology/core#contributingRole" ;
:hasOutgoingProperty "http://purl.obolibrary.org/obo/RO_0000052" .
# ------------------------------------ # ------------------------------------

View file

@ -36,8 +36,10 @@ import edu.cornell.mannlib.vitro.webapp.utils.configuration.Validation;
* individual should include the labels of the partners across those nodes. The * individual should include the labels of the partners across those nodes. The
* labels will be added to the ALLTEXT and ALLTEXTUNSTEMMED fields. * labels will be added to the ALLTEXT and ALLTEXTUNSTEMMED fields.
* *
* We can add restrictions to say that this only applies to individuals of * We must specify what property leads to a context node (incoming), and what
* certain types. We can also restrict the type of the applicable context nodes. * property leads from a context node (outgoing). We may add restrictions to say
* that this only applies to individuals of certain types. We may also restrict
* the type of the applicable context nodes.
* *
* An instance of this class acts as both a DocumentModifier and an * An instance of this class acts as both a DocumentModifier and an
* IndexingUriFinder: * IndexingUriFinder:
@ -52,6 +54,8 @@ import edu.cornell.mannlib.vitro.webapp.utils.configuration.Validation;
* <pre> * <pre>
* Configuration: * Configuration:
* rdfs:label -- Optional. Appears in the timings and debug statements. * rdfs:label -- Optional. Appears in the timings and debug statements.
* :hasIncomingProperty -- Required. Property leading to the context node.
* :hasOutgoingProperty -- Required. Property leading from the context node.
* :hasTypeRestriction -- Optional. Match any. If none, then no restriction. * :hasTypeRestriction -- Optional. Match any. If none, then no restriction.
* :appliesToContextNodeType -- Optional. Match any. If none, then no restriction. * :appliesToContextNodeType -- Optional. Match any. If none, then no restriction.
* </pre> * </pre>
@ -69,6 +73,16 @@ public class LabelsAcrossContextNodes implements IndexingUriFinder,
*/ */
private String label; private String label;
/**
* The URI of the property that leads into the context node. Required.
*/
private String incomingPropertyUri;
/**
* The URI of the property that leads from the context node. Required.
*/
private String outgoingPropertyUri;
/** /**
* URIs of the types of individuals to whom this instance applies. * URIs of the types of individuals to whom this instance applies.
* *
@ -95,6 +109,28 @@ public class LabelsAcrossContextNodes implements IndexingUriFinder,
label = l; label = l;
} }
@Property(uri = "http://vitro.mannlib.cornell.edu/ns/vitro/ApplicationSetup#hasIncomingProperty")
public void setIncomingProperty(String incomingUri) {
if (incomingPropertyUri == null) {
incomingPropertyUri = incomingUri;
} else {
throw new IllegalStateException(
"Configuration includes multiple declarations for hasIncomingProperty: "
+ incomingPropertyUri + ", and " + incomingUri);
}
}
@Property(uri = "http://vitro.mannlib.cornell.edu/ns/vitro/ApplicationSetup#hasOutgoingProperty")
public void setOutgoingProperty(String outgoingUri) {
if (outgoingPropertyUri == null) {
outgoingPropertyUri = outgoingUri;
} else {
throw new IllegalStateException(
"Configuration includes multiple declarations for hasOutgoingProperty: "
+ outgoingPropertyUri + ", and " + outgoingUri);
}
}
@Property(uri = "http://vitro.mannlib.cornell.edu/ns/vitro/ApplicationSetup#hasTypeRestriction") @Property(uri = "http://vitro.mannlib.cornell.edu/ns/vitro/ApplicationSetup#hasTypeRestriction")
public void addTypeRestriction(String typeUri) { public void addTypeRestriction(String typeUri) {
typeRestrictions.add(typeUri); typeRestrictions.add(typeUri);
@ -113,6 +149,14 @@ public class LabelsAcrossContextNodes implements IndexingUriFinder,
formatRestrictions(typeRestrictions), formatRestrictions(typeRestrictions),
formatRestrictions(contextNodeClasses)); formatRestrictions(contextNodeClasses));
} }
if (incomingPropertyUri == null) {
throw new IllegalStateException(
"Configuration did not declare hasIncomingProperty.");
}
if (outgoingPropertyUri == null) {
throw new IllegalStateException(
"Configuration did not declare hasOutgoingProperty.");
}
} }
private String formatRestrictions(Set<String> uris) { private String formatRestrictions(Set<String> uris) {
@ -146,23 +190,21 @@ public class LabelsAcrossContextNodes implements IndexingUriFinder,
// ---------------------------------------------------------------------- // ----------------------------------------------------------------------
private static final String LABELS_WITHOUT_RESTRICTION = "" private static final String LABELS_WITHOUT_RESTRICTION = ""
+ "PREFIX vivo: <http://vivoweb.org/ontology/core#> \n"
+ "PREFIX rdfs: <http://www.w3.org/2000/01/rdf-schema#> \n" + "PREFIX rdfs: <http://www.w3.org/2000/01/rdf-schema#> \n"
+ "SELECT ?label \n" // + "SELECT ?label \n" //
+ "WHERE { \n" // + "WHERE { \n" //
+ " ?uri vivo:relatedBy ?contextNode . \n" // + " ?uri ?incoming ?contextNode . \n" //
+ " ?contextNode vivo:relates ?partner . \n" // + " ?contextNode ?outgoing ?partner . \n" //
+ " ?partner rdfs:label ?label . \n" // + " ?partner rdfs:label ?label . \n" //
+ " FILTER( ?uri != ?partner ) \n" // + " FILTER( ?uri != ?partner ) \n" //
+ "} \n"; + "} \n";
private static final String LABELS_FOR_SPECIFIC_CONTEXT_NODE_TYPE = "" private static final String LABELS_FOR_SPECIFIC_CONTEXT_NODE_TYPE = ""
+ "PREFIX vivo: <http://vivoweb.org/ontology/core#> \n"
+ "PREFIX rdfs: <http://www.w3.org/2000/01/rdf-schema#> \n" + "PREFIX rdfs: <http://www.w3.org/2000/01/rdf-schema#> \n"
+ "SELECT ?label \n" // + "SELECT ?label \n" //
+ "WHERE { \n" // + "WHERE { \n" //
+ " ?uri vivo:relatedBy ?contextNode . \n" // + " ?uri ?incoming ?contextNode . \n" //
+ " ?contextNode a ?nodeType . \n" // + " ?contextNode a ?nodeType . \n" //
+ " ?contextNode vivo:relates ?partner . \n" // + " ?contextNode ?outgoing ?partner . \n" //
+ " ?partner rdfs:label ?label . \n" // + " ?partner rdfs:label ?label . \n" //
+ " FILTER( ?uri != ?partner ) \n" // + " FILTER( ?uri != ?partner ) \n" //
+ "} \n"; + "} \n";
@ -202,8 +244,10 @@ public class LabelsAcrossContextNodes implements IndexingUriFinder,
SearchInputDocument doc) { SearchInputDocument doc) {
addValuesToTextFields(doc, addValuesToTextFields(doc,
createQueryContext(rdfService, LABELS_WITHOUT_RESTRICTION) createQueryContext(rdfService, LABELS_WITHOUT_RESTRICTION)
.bindVariableToUri("uri", ind.getURI()).execute() .bindVariableToUri("uri", ind.getURI())
.getStringFields("label").flatten()); .bindVariableToUri("incoming", incomingPropertyUri)
.bindVariableToUri("outgoing", outgoingPropertyUri)
.execute().getStringFields("label").flatten());
} }
private void addLabelsFromContextNodeClass(Individual ind, private void addLabelsFromContextNodeClass(Individual ind,
@ -214,6 +258,8 @@ public class LabelsAcrossContextNodes implements IndexingUriFinder,
LABELS_FOR_SPECIFIC_CONTEXT_NODE_TYPE) LABELS_FOR_SPECIFIC_CONTEXT_NODE_TYPE)
.bindVariableToUri("uri", ind.getURI()) .bindVariableToUri("uri", ind.getURI())
.bindVariableToUri("nodeType", contextNodeClass) .bindVariableToUri("nodeType", contextNodeClass)
.bindVariableToUri("incoming", incomingPropertyUri)
.bindVariableToUri("outgoing", outgoingPropertyUri)
.execute().getStringFields("label").flatten()); .execute().getStringFields("label").flatten());
} }
@ -234,30 +280,25 @@ public class LabelsAcrossContextNodes implements IndexingUriFinder,
// IndexingUriFinder // IndexingUriFinder
// ---------------------------------------------------------------------- // ----------------------------------------------------------------------
private static final String URI_VIVO_RELATES = "http://vivoweb.org/ontology/core#relates";
private static final String LOCATE_PARTNERS_WITHOUT_RESTRICTION = "" private static final String LOCATE_PARTNERS_WITHOUT_RESTRICTION = ""
+ "PREFIX vivo: <http://vivoweb.org/ontology/core#> \n"
+ "SELECT ?partner \n" // + "SELECT ?partner \n" //
+ "WHERE { \n" // + "WHERE { \n" //
+ " ?uri vivo:relatedBy ?contextNode . \n" // + " ?uri ?incoming ?contextNode . \n" //
+ " ?contextNode vivo:relates ?partner . \n" // + " ?contextNode ?outgoing ?partner . \n" //
+ " FILTER( ?uri != ?partner ) \n" // + " FILTER( ?uri != ?partner ) \n" //
+ "} \n"; + "} \n";
private static final String LOCATE_PARTNERS_ON_CONTEXT_NODE_TYPE = "" private static final String LOCATE_PARTNERS_ON_CONTEXT_NODE_TYPE = ""
+ "PREFIX vivo: <http://vivoweb.org/ontology/core#> \n"
+ "SELECT ?partner \n" // + "SELECT ?partner \n" //
+ "WHERE { \n" // + "WHERE { \n" //
+ " ?uri vivo:relatedBy ?contextNode . \n" // + " ?uri ?incoming ?contextNode . \n" //
+ " ?contextNode vivo:relates ?partner . \n" // + " ?contextNode ?outgoing ?partner . \n" //
+ " ?contextNode a ?nodeType . \n" // + " ?contextNode a ?nodeType . \n" //
+ " FILTER( ?uri != ?partner ) \n" // + " FILTER( ?uri != ?partner ) \n" //
+ "} \n"; + "} \n";
private static final String LOCATE_OTHER_PARTNERS_ON_THIS_NODE = "" private static final String LOCATE_OTHER_PARTNERS_ON_THIS_NODE = ""
+ "PREFIX vivo: <http://vivoweb.org/ontology/core#> \n"
+ "SELECT ?partner \n" // + "SELECT ?partner \n" //
+ "WHERE { \n" // + "WHERE { \n" //
+ " ?contextNode vivo:relates ?partner . \n" // + " ?contextNode ?outgoing ?partner . \n" //
+ " FILTER( ?uri != ?partner ) \n" // + " FILTER( ?uri != ?partner ) \n" //
+ "} \n"; + "} \n";
private static final String GET_TYPES = "" // private static final String GET_TYPES = "" //
@ -275,17 +316,18 @@ public class LabelsAcrossContextNodes implements IndexingUriFinder,
* If this is a "label" statement, check to see if the subject has any * If this is a "label" statement, check to see if the subject has any
* acceptable partners across acceptable context nodes. * acceptable partners across acceptable context nodes.
* *
* If this is a "relates" statement on an acceptable context node, check to * If this is a statement that involves the specified outgoing property on
* see if there are any other acceptable partners on this node. * an acceptable context node, check to see if there are any other
* acceptable partners on this node.
* *
* We could also check for "relatedBy" statements, but they should happen in * We could also check for statements that involve the specified incoming
* pairs with the "relates" statements. * property, but they should happen in pairs with the "outgoing" statements.
*/ */
@Override @Override
public List<String> findAdditionalURIsToIndex(Statement stmt) { public List<String> findAdditionalURIsToIndex(Statement stmt) {
if (isLabelStatement(stmt)) { if (isLabelStatement(stmt)) {
return filterByType(locatePartners(stmt)); return filterByType(locatePartners(stmt));
} else if (isRelatesStatementOnAcceptableContextNode(stmt)) { } else if (isOutgoingStatementOnAcceptableContextNode(stmt)) {
return filterByType(locateOtherPartners(stmt)); return filterByType(locateOtherPartners(stmt));
} }
return Collections.emptyList(); return Collections.emptyList();
@ -312,7 +354,9 @@ public class LabelsAcrossContextNodes implements IndexingUriFinder,
private Set<String> locatePartnersWithoutRestriction(String uri) { private Set<String> locatePartnersWithoutRestriction(String uri) {
return createQueryContext(rdfService, return createQueryContext(rdfService,
LOCATE_PARTNERS_WITHOUT_RESTRICTION) LOCATE_PARTNERS_WITHOUT_RESTRICTION)
.bindVariableToUri("uri", uri).execute() .bindVariableToUri("uri", uri)
.bindVariableToUri("incoming", incomingPropertyUri)
.bindVariableToUri("outgoing", outgoingPropertyUri).execute()
.getStringFields("partner").flattenToSet(); .getStringFields("partner").flattenToSet();
} }
@ -321,15 +365,17 @@ public class LabelsAcrossContextNodes implements IndexingUriFinder,
return createQueryContext(rdfService, return createQueryContext(rdfService,
LOCATE_PARTNERS_ON_CONTEXT_NODE_TYPE) LOCATE_PARTNERS_ON_CONTEXT_NODE_TYPE)
.bindVariableToUri("uri", uri) .bindVariableToUri("uri", uri)
.bindVariableToUri("nodeType", contextNodeClass).execute() .bindVariableToUri("nodeType", contextNodeClass)
.bindVariableToUri("incoming", incomingPropertyUri)
.bindVariableToUri("outgoing", outgoingPropertyUri).execute()
.getStringFields("partner").flattenToSet(); .getStringFields("partner").flattenToSet();
} }
private boolean isRelatesStatementOnAcceptableContextNode(Statement stmt) { private boolean isOutgoingStatementOnAcceptableContextNode(Statement stmt) {
String subjectUri = stmt.getSubject().getURI(); String subjectUri = stmt.getSubject().getURI();
String predicateUri = stmt.getPredicate().getURI(); String predicateUri = stmt.getPredicate().getURI();
if (URI_VIVO_RELATES.equals(predicateUri) if (outgoingPropertyUri.equals(predicateUri)
&& (contextNodeClasses.isEmpty() || isAnyMatch( && (contextNodeClasses.isEmpty() || isAnyMatch(
contextNodeClasses, getTypes(subjectUri)))) { contextNodeClasses, getTypes(subjectUri)))) {
return true; return true;
@ -362,7 +408,8 @@ public class LabelsAcrossContextNodes implements IndexingUriFinder,
return createQueryContext(rdfService, return createQueryContext(rdfService,
LOCATE_OTHER_PARTNERS_ON_THIS_NODE) LOCATE_OTHER_PARTNERS_ON_THIS_NODE)
.bindVariableToUri("contextNode", nodeUri) .bindVariableToUri("contextNode", nodeUri)
.bindVariableToUri("uri", objectUri).execute() .bindVariableToUri("uri", objectUri)
.bindVariableToUri("outgoing", outgoingPropertyUri).execute()
.getStringFields("partner").flattenToSet(); .getStringFields("partner").flattenToSet();
} }

View file

@ -126,6 +126,9 @@ public class LabelsAcrossContextNodesTest extends AbstractTestClass {
lacn = new LabelsAcrossContextNodes(); lacn = new LabelsAcrossContextNodes();
lacn.setContextModels(models); lacn.setContextModels(models);
lacn.setIncomingProperty(CORE_RELATED_BY);
lacn.setOutgoingProperty(CORE_RELATES);
lacn.validate();
} }
// ---------------------------------------------------------------------- // ----------------------------------------------------------------------