You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@rya.apache.org by ca...@apache.org on 2017/08/19 02:04:24 UTC
incubator-rya git commit: RYA-295 owl:allValuesFrom inference. Closes
#201.
Repository: incubator-rya
Updated Branches:
refs/heads/master 0d80871ff -> 2e88f1050
RYA-295 owl:allValuesFrom inference. Closes #201.
Project: http://git-wip-us.apache.org/repos/asf/incubator-rya/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-rya/commit/2e88f105
Tree: http://git-wip-us.apache.org/repos/asf/incubator-rya/tree/2e88f105
Diff: http://git-wip-us.apache.org/repos/asf/incubator-rya/diff/2e88f105
Branch: refs/heads/master
Commit: 2e88f1050b095ade37586562398cd02e162da639
Parents: 0d80871
Author: Jesse Hatfield <je...@parsons.com>
Authored: Tue Aug 8 15:58:10 2017 -0400
Committer: Caleb Meier <ca...@parsons.com>
Committed: Fri Aug 18 19:03:46 2017 -0700
----------------------------------------------------------------------
.../src/main/java/MongoRyaDirectExample.java | 52 ++++++++
.../RdfCloudTripleStoreConnection.java | 2 +
.../inference/AllValuesFromVisitor.java | 112 ++++++++++++++++
.../inference/InferenceEngine.java | 81 +++++++++++-
.../inference/AllValuesFromVisitorTest.java | 128 +++++++++++++++++++
.../inference/InferenceEngineTest.java | 31 +++++
.../rdftriplestore/inference/InferenceIT.java | 37 ++++++
7 files changed, 440 insertions(+), 3 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/incubator-rya/blob/2e88f105/extras/indexingExample/src/main/java/MongoRyaDirectExample.java
----------------------------------------------------------------------
diff --git a/extras/indexingExample/src/main/java/MongoRyaDirectExample.java b/extras/indexingExample/src/main/java/MongoRyaDirectExample.java
index 32de913..1294a44 100644
--- a/extras/indexingExample/src/main/java/MongoRyaDirectExample.java
+++ b/extras/indexingExample/src/main/java/MongoRyaDirectExample.java
@@ -26,6 +26,7 @@ import org.apache.log4j.Logger;
import org.openrdf.model.Namespace;
import org.openrdf.model.URI;
import org.openrdf.model.ValueFactory;
+import org.openrdf.model.vocabulary.OWL;
import org.openrdf.model.vocabulary.RDF;
import org.openrdf.model.vocabulary.RDFS;
import org.openrdf.query.BindingSet;
@@ -98,6 +99,7 @@ public class MongoRyaDirectExample {
testInfer(conn, sail);
testPropertyChainInference(conn, sail);
testPropertyChainInferenceAltRepresentation(conn, sail);
+ testAllValuesFromInference(conn, sail);
}
log.info("TIME: " + (System.currentTimeMillis() - start) / 1000.);
@@ -446,6 +448,56 @@ public class MongoRyaDirectExample {
log.info("Result count : " + resultHandler.getCount());
}
+
+ public static void testAllValuesFromInference(SailRepositoryConnection conn, Sail sail) throws MalformedQueryException, RepositoryException,
+ UpdateExecutionException, QueryEvaluationException, TupleQueryResultHandlerException, InferenceEngineException {
+ log.info("Adding Data");
+ String insert = "INSERT DATA\n"
+ + "{ GRAPH <http://updated/test> {\n"
+ + " <urn:Alice> a <urn:Person> .\n"
+ + " <urn:Alice> <urn:hasParent> <urn:Bob> .\n"
+ + " <urn:Carol> <urn:hasParent> <urn:Dan> .\n"
+ + "}}";
+ Update update = conn.prepareUpdate(QueryLanguage.SPARQL, insert);
+ update.execute();
+ final String inferQuery = "select distinct ?x { GRAPH <http://updated/test> { ?x a <urn:Person> }}";
+ final String explicitQuery = "select distinct ?x { GRAPH <http://updated/test> {\n"
+ + " { ?x a <urn:Person> }\n"
+ + " UNION {\n"
+ + " ?y a <urn:Person> .\n"
+ + " ?y <urn:hasParent> ?x .\n"
+ + " }\n"
+ + "}}";
+ log.info("Running Explicit Query");
+ CountingResultHandler resultHandler = new CountingResultHandler();
+ TupleQuery tupleQuery = conn.prepareTupleQuery(QueryLanguage.SPARQL, explicitQuery);
+ tupleQuery.evaluate(resultHandler);
+ log.info("Result count : " + resultHandler.getCount());
+ Validate.isTrue(resultHandler.getCount() == 2);
+ log.info("Running Inference-dependent Query");
+ resultHandler.resetCount();
+ tupleQuery = conn.prepareTupleQuery(QueryLanguage.SPARQL, inferQuery);
+ tupleQuery.evaluate(resultHandler);
+ log.info("Result count : " + resultHandler.getCount());
+ Validate.isTrue(resultHandler.getCount() == 1);
+ log.info("Adding owl:allValuesFrom Schema");
+ insert = "PREFIX rdfs: <" + RDFS.NAMESPACE + ">\n"
+ + "PREFIX owl: <" + OWL.NAMESPACE + ">\n"
+ + "INSERT DATA\n"
+ + "{ GRAPH <http://updated/test> {\n"
+ + " <urn:Person> rdfs:subClassOf [ owl:onProperty <urn:hasParent> ; owl:allValuesFrom <urn:Person> ] ."
+ + "}}";
+ update = conn.prepareUpdate(QueryLanguage.SPARQL, insert);
+ update.execute();
+ log.info("Refreshing InferenceEngine");
+ ((RdfCloudTripleStore) sail).getInferenceEngine().refreshGraph();
+ log.info("Re-running Inference-dependent Query");
+ resultHandler.resetCount();
+ tupleQuery = conn.prepareTupleQuery(QueryLanguage.SPARQL, inferQuery);
+ tupleQuery.evaluate(resultHandler);
+ log.info("Result count : " + resultHandler.getCount());
+ Validate.isTrue(resultHandler.getCount() == 2);
+ }
public static void testInfer(SailRepositoryConnection conn, Sail sail) throws MalformedQueryException, RepositoryException,
UpdateExecutionException, QueryEvaluationException, TupleQueryResultHandlerException, InferenceEngineException {
http://git-wip-us.apache.org/repos/asf/incubator-rya/blob/2e88f105/sail/src/main/java/org/apache/rya/rdftriplestore/RdfCloudTripleStoreConnection.java
----------------------------------------------------------------------
diff --git a/sail/src/main/java/org/apache/rya/rdftriplestore/RdfCloudTripleStoreConnection.java b/sail/src/main/java/org/apache/rya/rdftriplestore/RdfCloudTripleStoreConnection.java
index 483d4ee..ec93da8 100644
--- a/sail/src/main/java/org/apache/rya/rdftriplestore/RdfCloudTripleStoreConnection.java
+++ b/sail/src/main/java/org/apache/rya/rdftriplestore/RdfCloudTripleStoreConnection.java
@@ -50,6 +50,7 @@ import org.apache.rya.rdftriplestore.evaluation.QueryJoinSelectOptimizer;
import org.apache.rya.rdftriplestore.evaluation.RdfCloudTripleStoreEvaluationStatistics;
import org.apache.rya.rdftriplestore.evaluation.RdfCloudTripleStoreSelectivityEvaluationStatistics;
import org.apache.rya.rdftriplestore.evaluation.SeparateFilterJoinsVisitor;
+import org.apache.rya.rdftriplestore.inference.AllValuesFromVisitor;
import org.apache.rya.rdftriplestore.inference.DomainRangeVisitor;
import org.apache.rya.rdftriplestore.inference.HasValueVisitor;
import org.apache.rya.rdftriplestore.inference.InferenceEngine;
@@ -351,6 +352,7 @@ public class RdfCloudTripleStoreConnection extends SailConnectionBase {
) {
try {
tupleExpr.visit(new DomainRangeVisitor(queryConf, inferenceEngine));
+ tupleExpr.visit(new AllValuesFromVisitor(queryConf, inferenceEngine));
tupleExpr.visit(new HasValueVisitor(queryConf, inferenceEngine));
tupleExpr.visit(new PropertyChainVisitor(queryConf, inferenceEngine));
tupleExpr.visit(new TransitivePropertyVisitor(queryConf, inferenceEngine));
http://git-wip-us.apache.org/repos/asf/incubator-rya/blob/2e88f105/sail/src/main/java/org/apache/rya/rdftriplestore/inference/AllValuesFromVisitor.java
----------------------------------------------------------------------
diff --git a/sail/src/main/java/org/apache/rya/rdftriplestore/inference/AllValuesFromVisitor.java b/sail/src/main/java/org/apache/rya/rdftriplestore/inference/AllValuesFromVisitor.java
new file mode 100644
index 0000000..9fc297a
--- /dev/null
+++ b/sail/src/main/java/org/apache/rya/rdftriplestore/inference/AllValuesFromVisitor.java
@@ -0,0 +1,112 @@
+package org.apache.rya.rdftriplestore.inference;
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import java.util.Map;
+import java.util.Set;
+import java.util.UUID;
+
+import org.apache.rya.api.RdfCloudTripleStoreConfiguration;
+import org.apache.rya.api.utils.NullableStatementImpl;
+import org.apache.rya.rdftriplestore.utils.FixedStatementPattern;
+import org.openrdf.model.Resource;
+import org.openrdf.model.URI;
+import org.openrdf.model.vocabulary.OWL;
+import org.openrdf.model.vocabulary.RDF;
+import org.openrdf.query.algebra.StatementPattern;
+import org.openrdf.query.algebra.Var;
+
+/**
+ * Expands the query tree to account for any universal class expressions (property restrictions
+ * using owl:allValuesFrom) in the ontology known to the {@link InferenceEngine}.
+ *
+ * Operates on {@link StatementPattern} nodes whose predicate is rdf:type and whose object is a
+ * defined type (not a variable) which is related to an allValuesFrom expression in the ontology.
+ * When applicable, replaces the node with a union of itself and a subtree that matches any
+ * instance that can be inferred to have the type in question via the semantics of
+ * owl:allValuesFrom.
+ *
+ * A universal class expression references a predicate and a value class, and represents the set of
+ * individuals who, for any instance of the predicate, have a value belonging to the value class.
+ * Therefore, the value class should be inferred for any individual which is the object of a triple
+ * with that predicate and with a subject belonging to the class expression. This implication is
+ * similar to rdfs:range except that it only applies when the subject of the triple belongs to a
+ * specific type.
+ *
+ * (Note: Because of OWL's open world assumption, the inference in the other direction can't be
+ * made. That is, when an individual is explicitly declared to have the universally quantified
+ * restriction, then the types of its values can be inferred. But when the universal restriction
+ * isn't explicitly stated, it can't be inferred from the values themselves, because there's no
+ * guarantee that all values are known.)
+ */
+public class AllValuesFromVisitor extends AbstractInferVisitor {
+
+ /**
+ * Creates a new {@link AllValuesFromVisitor}, which is enabled by default.
+ * @param conf The {@link RdfCloudTripleStoreConfiguration}.
+ * @param inferenceEngine The InferenceEngine containing the relevant ontology.
+ */
+ public AllValuesFromVisitor(RdfCloudTripleStoreConfiguration conf, InferenceEngine inferenceEngine) {
+ super(conf, inferenceEngine);
+ include = true;
+ }
+
+ /**
+ * Checks whether the StatementPattern is a type query whose solutions could be inferred
+ * by allValuesFrom inference, and if so, replaces the node with a union of itself and any
+ * possible inference.
+ */
+ @Override
+ protected void meetSP(StatementPattern node) throws Exception {
+ final Var subjVar = node.getSubjectVar();
+ final Var predVar = node.getPredicateVar();
+ final Var objVar = node.getObjectVar();
+ // Only applies to type queries where the type is defined
+ if (predVar != null && RDF.TYPE.equals(predVar.getValue()) && objVar != null && objVar.getValue() instanceof Resource) {
+ final Resource typeToInfer = (Resource) objVar.getValue();
+ Map<Resource, Set<URI>> relevantAvfRestrictions = inferenceEngine.getAllValuesFromByValueType(typeToInfer);
+ if (!relevantAvfRestrictions.isEmpty()) {
+ // We can infer the queried type if, for an allValuesFrom restriction type
+ // associated with the queried type, some anonymous neighboring node belongs to the
+ // restriction type and has the node in question (subjVar) as a value for the
+ // restriction's property.
+ final Var avfTypeVar = new Var("t-" + UUID.randomUUID());
+ final Var avfPredVar = new Var("p-" + UUID.randomUUID());
+ final Var neighborVar = new Var("n-" + UUID.randomUUID());
+ neighborVar.setAnonymous(true);
+ final StatementPattern membershipPattern = new DoNotExpandSP(neighborVar,
+ new Var(RDF.TYPE.stringValue(), RDF.TYPE), avfTypeVar);
+ final StatementPattern valuePattern = new StatementPattern(neighborVar, avfPredVar, subjVar);
+ final InferJoin avfPattern = new InferJoin(membershipPattern, valuePattern);
+ // Use a FixedStatementPattern to contain the appropriate (restriction, predicate)
+ // pairs, and check each one against the general pattern.
+ final FixedStatementPattern avfPropertyTypes = new FixedStatementPattern(avfTypeVar,
+ new Var(OWL.ONPROPERTY.stringValue(), OWL.ONPROPERTY), avfPredVar);
+ for (Resource avfRestrictionType : relevantAvfRestrictions.keySet()) {
+ for (URI avfProperty : relevantAvfRestrictions.get(avfRestrictionType)) {
+ avfPropertyTypes.statements.add(new NullableStatementImpl(avfRestrictionType,
+ OWL.ONPROPERTY, avfProperty));
+ }
+ }
+ final InferJoin avfInferenceQuery = new InferJoin(avfPropertyTypes, avfPattern);
+ node.replaceWith(new InferUnion(node.clone(), avfInferenceQuery));
+ }
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-rya/blob/2e88f105/sail/src/main/java/org/apache/rya/rdftriplestore/inference/InferenceEngine.java
----------------------------------------------------------------------
diff --git a/sail/src/main/java/org/apache/rya/rdftriplestore/inference/InferenceEngine.java b/sail/src/main/java/org/apache/rya/rdftriplestore/inference/InferenceEngine.java
index 43f00e0..05b847b 100644
--- a/sail/src/main/java/org/apache/rya/rdftriplestore/inference/InferenceEngine.java
+++ b/sail/src/main/java/org/apache/rya/rdftriplestore/inference/InferenceEngine.java
@@ -73,10 +73,11 @@ public class InferenceEngine {
private Set<URI> symmetricPropertySet;
private Map<URI, URI> inverseOfMap;
private Set<URI> transitivePropertySet;
- private Map<Resource, Map<URI, Value>> hasValueByType;
- private Map<URI, Map<Resource, Value>> hasValueByProperty;
private Map<URI, Set<URI>> domainByType;
private Map<URI, Set<URI>> rangeByType;
+ private Map<Resource, Map<URI, Value>> hasValueByType;
+ private Map<URI, Map<Resource, Value>> hasValueByProperty;
+ private Map<Resource, Map<Resource, URI>> allValuesFromByValueType;
private RyaDAO ryaDAO;
private RdfCloudTripleStoreConfiguration conf;
@@ -589,8 +590,9 @@ public class InferenceEngine {
iter.close();
}
}
- // Query for the hasValue restrictions and add them to the schema
+ // Query for specific types of restriction and add their details to the schema
refreshHasValueRestrictions(restrictions);
+ refreshAllValuesFromRestrictions(restrictions);
}
private void refreshHasValueRestrictions(Map<Resource, URI> restrictions) throws QueryEvaluationException {
@@ -621,6 +623,36 @@ public class InferenceEngine {
}
}
+ private void refreshAllValuesFromRestrictions(Map<Resource, URI> restrictions) throws QueryEvaluationException {
+ allValuesFromByValueType = new HashMap<>();
+ CloseableIteration<Statement, QueryEvaluationException> iter = RyaDAOHelper.query(ryaDAO, null, OWL.ALLVALUESFROM, null, conf);
+ try {
+ while (iter.hasNext()) {
+ Statement st = iter.next();
+ if (restrictions.containsKey(st.getSubject()) && st.getObject() instanceof URI) {
+ URI property = restrictions.get(st.getSubject());
+ URI valueClass = (URI) st.getObject();
+ // Should also be triggered by subclasses of the property restriction
+ Set<Resource> restrictionClasses = new HashSet<>();
+ restrictionClasses.add(st.getSubject());
+ if (st.getSubject() instanceof URI) {
+ restrictionClasses.addAll(findParents(subClassOfGraph, (URI) st.getSubject()));
+ }
+ for (Resource restrictionClass : restrictionClasses) {
+ if (!allValuesFromByValueType.containsKey(valueClass)) {
+ allValuesFromByValueType.put(valueClass, new HashMap<>());
+ }
+ allValuesFromByValueType.get(valueClass).put(restrictionClass, property);
+ }
+ }
+ }
+ } finally {
+ if (iter != null) {
+ iter.close();
+ }
+ }
+ }
+
private static Vertex getVertex(Graph graph, Object id) {
Iterator<Vertex> it = graph.vertices(id.toString());
if (it.hasNext()) {
@@ -947,4 +979,47 @@ public class InferenceEngine {
}
return properties;
}
+
+ /**
+ * For a given type, return information about any owl:allValuesFrom restriction that could imply
+ * an individual's membership in that type: If the subject of a triple belongs to the type
+ * associated with the restriction itself, and the predicate is the one referenced by the
+ * restriction, then the object of the triple is implied to have the value type.
+ * @param valueType The type to be inferred, which is the type of the object of the triple, or
+ * the type from which all values are stated to belong. Takes class hierarchy into account,
+ * so possible inferences include any ways of inferring subtypes of the value type, and
+ * subject types that trigger inference include any subtypes of relevant restrictions.
+ * Also considers property hierarchy, so properties that trigger inference will include
+ * subproperties of those referenced by relevant restrictions.
+ * @return A map from subject type (a property restriction type or a subtype of one) to the set
+ * of properties (including any property referenced by such a restriction and all of its
+ * subproperties) such that for any individual which belongs to the subject type, all
+ * values it has for any of those properties belong to the value type.
+ */
+ public Map<Resource, Set<URI>> getAllValuesFromByValueType(Resource valueType) {
+ Map<Resource, Set<URI>> implications = new HashMap<>();
+ if (allValuesFromByValueType != null) {
+ // Check for any subtypes which would in turn imply the value type
+ HashSet<Resource> valueTypes = new HashSet<>();
+ valueTypes.add(valueType);
+ if (valueType instanceof URI) {
+ valueTypes.addAll(findParents(subClassOfGraph, (URI) valueType));
+ }
+ for (Resource valueSubType : valueTypes) {
+ if (allValuesFromByValueType.containsKey(valueSubType)) {
+ Map<Resource, URI> restrictionToProperty = allValuesFromByValueType.get(valueSubType);
+ for (Resource restrictionType : restrictionToProperty.keySet()) {
+ if (!implications.containsKey(restrictionType)) {
+ implications.put(restrictionType, new HashSet<>());
+ }
+ URI property = restrictionToProperty.get(restrictionType);
+ implications.get(restrictionType).add(property);
+ // Also add subproperties that would in turn imply the property
+ implications.get(restrictionType).addAll(findParents(subPropertyOfGraph, property));
+ }
+ }
+ }
+ }
+ return implications;
+ }
}
http://git-wip-us.apache.org/repos/asf/incubator-rya/blob/2e88f105/sail/src/test/java/org/apache/rya/rdftriplestore/inference/AllValuesFromVisitorTest.java
----------------------------------------------------------------------
diff --git a/sail/src/test/java/org/apache/rya/rdftriplestore/inference/AllValuesFromVisitorTest.java b/sail/src/test/java/org/apache/rya/rdftriplestore/inference/AllValuesFromVisitorTest.java
new file mode 100644
index 0000000..d284d57
--- /dev/null
+++ b/sail/src/test/java/org/apache/rya/rdftriplestore/inference/AllValuesFromVisitorTest.java
@@ -0,0 +1,128 @@
+package org.apache.rya.rdftriplestore.inference;
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+
+import org.apache.rya.accumulo.AccumuloRdfConfiguration;
+import org.apache.rya.api.utils.NullableStatementImpl;
+import org.apache.rya.rdftriplestore.utils.FixedStatementPattern;
+import org.junit.Assert;
+import org.junit.Test;
+import org.openrdf.model.Resource;
+import org.openrdf.model.URI;
+import org.openrdf.model.ValueFactory;
+import org.openrdf.model.impl.ValueFactoryImpl;
+import org.openrdf.model.vocabulary.OWL;
+import org.openrdf.model.vocabulary.RDF;
+import org.openrdf.query.algebra.Join;
+import org.openrdf.query.algebra.Projection;
+import org.openrdf.query.algebra.ProjectionElem;
+import org.openrdf.query.algebra.ProjectionElemList;
+import org.openrdf.query.algebra.StatementPattern;
+import org.openrdf.query.algebra.TupleExpr;
+import org.openrdf.query.algebra.Union;
+import org.openrdf.query.algebra.Var;
+
+public class AllValuesFromVisitorTest {
+ private final AccumuloRdfConfiguration conf = new AccumuloRdfConfiguration();
+ private final ValueFactory vf = new ValueFactoryImpl();
+
+ // Value types
+ private final URI person = vf.createURI("urn:Person");
+ private final URI dog = vf.createURI("urn:Dog");
+ // Predicates
+ private final URI parent = vf.createURI("urn:parent");
+ private final URI relative = vf.createURI("urn:relative");
+ // Restriction types
+ private final URI parentsAreTallPeople = vf.createURI("urn:parentsAreTallPeople");
+ private final URI parentsArePeople = vf.createURI("urn:parentsArePeople");
+ private final URI relativesArePeople = vf.createURI("urn:relativesArePeople");
+ private final URI parentsAreDogs = vf.createURI("urn:parentsAreDogs");
+
+ @Test
+ public void testRewriteTypePattern() throws Exception {
+ // Configure a mock instance engine with an ontology:
+ final InferenceEngine inferenceEngine = mock(InferenceEngine.class);
+ Map<Resource, Set<URI>> personAVF = new HashMap<>();
+ personAVF.put(parentsAreTallPeople, new HashSet<>());
+ personAVF.put(parentsArePeople, new HashSet<>());
+ personAVF.put(relativesArePeople, new HashSet<>());
+ personAVF.get(parentsAreTallPeople).add(parent);
+ personAVF.get(parentsArePeople).add(parent);
+ personAVF.get(relativesArePeople).add(relative);
+ personAVF.get(relativesArePeople).add(parent);
+ Map<Resource, Set<URI>> dogAVF = new HashMap<>();
+ dogAVF.put(parentsAreDogs, new HashSet<>());
+ dogAVF.get(parentsAreDogs).add(parent);
+ when(inferenceEngine.getAllValuesFromByValueType(person)).thenReturn(personAVF);
+ when(inferenceEngine.getAllValuesFromByValueType(dog)).thenReturn(dogAVF);
+ // Query for a specific type and rewrite using the visitor:
+ StatementPattern originalSP = new StatementPattern(new Var("s"), new Var("p", RDF.TYPE), new Var("o", person));
+ final Projection query = new Projection(originalSP, new ProjectionElemList(new ProjectionElem("s", "subject")));
+ query.visit(new AllValuesFromVisitor(conf, inferenceEngine));
+ // Expected structure: a union of two elements: one is equal to the original statement
+ // pattern, and the other one joins a list of predicate/restriction type combinations
+ // with another join querying for values of that predicate for members of that type.
+ Assert.assertTrue(query.getArg() instanceof Union);
+ TupleExpr left = ((Union) query.getArg()).getLeftArg();
+ TupleExpr right = ((Union) query.getArg()).getRightArg();
+ final Join join;
+ if (left instanceof StatementPattern) {
+ Assert.assertEquals(originalSP, left);
+ Assert.assertTrue(right instanceof Join);
+ join = (Join) right;
+ }
+ else {
+ Assert.assertEquals(originalSP, right);
+ Assert.assertTrue(left instanceof Join);
+ join = (Join) left;
+ }
+ Assert.assertTrue(join.getLeftArg() instanceof FixedStatementPattern);
+ Assert.assertTrue(join.getRightArg() instanceof Join);
+ FixedStatementPattern fsp = (FixedStatementPattern) join.getLeftArg();
+ left = ((Join) join.getRightArg()).getLeftArg();
+ right = ((Join) join.getRightArg()).getRightArg();
+ Assert.assertTrue(left instanceof StatementPattern);
+ Assert.assertTrue(right instanceof StatementPattern);
+ // Verify expected predicate/restriction pairs
+ Assert.assertEquals(4, fsp.statements.size());
+ fsp.statements.contains(new NullableStatementImpl(parentsArePeople, OWL.ONPROPERTY, parent));
+ fsp.statements.contains(new NullableStatementImpl(relativesArePeople, OWL.ONPROPERTY, relative));
+ fsp.statements.contains(new NullableStatementImpl(relativesArePeople, OWL.ONPROPERTY, parent));
+ fsp.statements.contains(new NullableStatementImpl(parentsAreTallPeople, OWL.ONPROPERTY, parent));
+ // Verify general pattern for matching instances of each pair: Join on unknown subject; left
+ // triple states it belongs to the restriction while right triple relates it to the original
+ // subject variable by the relevant property. Restriction and property variables are given
+ // by the FixedStatementPattern.
+ StatementPattern leftSP = (StatementPattern) left;
+ StatementPattern rightSP = (StatementPattern) right;
+ Assert.assertEquals(rightSP.getSubjectVar(), leftSP.getSubjectVar());
+ Assert.assertEquals(RDF.TYPE, leftSP.getPredicateVar().getValue());
+ Assert.assertEquals(fsp.getSubjectVar(), leftSP.getObjectVar());
+ Assert.assertEquals(fsp.getObjectVar(), rightSP.getPredicateVar());
+ Assert.assertEquals(originalSP.getSubjectVar(), rightSP.getObjectVar());
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-rya/blob/2e88f105/sail/src/test/java/org/apache/rya/rdftriplestore/inference/InferenceEngineTest.java
----------------------------------------------------------------------
diff --git a/sail/src/test/java/org/apache/rya/rdftriplestore/inference/InferenceEngineTest.java b/sail/src/test/java/org/apache/rya/rdftriplestore/inference/InferenceEngineTest.java
index 31ea3e8..556413f 100644
--- a/sail/src/test/java/org/apache/rya/rdftriplestore/inference/InferenceEngineTest.java
+++ b/sail/src/test/java/org/apache/rya/rdftriplestore/inference/InferenceEngineTest.java
@@ -225,6 +225,37 @@ public class InferenceEngineTest extends TestCase {
}
@Test
+ public void testAllValuesFrom() throws Exception {
+ String insert = "INSERT DATA { GRAPH <http://updated/test> {\n"
+ + " <urn:Dog> owl:onProperty <urn:relative> ; owl:allValuesFrom <urn:Dog> .\n"
+ + " <urn:Retriever> rdfs:subClassOf <urn:Dog> .\n"
+ + " <urn:Terrier> rdfs:subClassOf <urn:Dog> .\n"
+ + " <urn:Terrier> owl:onProperty <urn:relative> ; owl:allValuesFrom <urn:Terrier> .\n"
+ + " <urn:Cairn_Terrier> rdfs:subClassOf <urn:Terrier> .\n"
+ + " <urn:parent> rdfs:subPropertyOf <urn:relative> .\n"
+ + " <urn:Dog> rdfs:subClassOf <urn:Mammal> .\n"
+ + " <urn:Person> rdfs:subClassOf <urn:Mammal> .\n"
+ + " <urn:Person> owl:onProperty <urn:relative> ; owl:allValuesFrom <urn:Person> .\n"
+ + "}}";
+ conn.prepareUpdate(QueryLanguage.SPARQL, insert).execute();
+ inferenceEngine.refreshGraph();
+ final Map<Resource, Set<URI>> restrictionsImplyingTerrier = new HashMap<>();
+ final Set<URI> properties = new HashSet<>();
+ properties.add(vf.createURI("urn:parent"));
+ properties.add(vf.createURI("urn:relative"));
+ restrictionsImplyingTerrier.put(vf.createURI("urn:Terrier"), properties);
+ restrictionsImplyingTerrier.put(vf.createURI("urn:Cairn_Terrier"), properties);
+ Assert.assertEquals(restrictionsImplyingTerrier, inferenceEngine.getAllValuesFromByValueType(vf.createURI("urn:Terrier")));
+ final Map<Resource, Set<URI>> restrictionsImplyingDog = new HashMap<>(restrictionsImplyingTerrier);
+ restrictionsImplyingDog.put(vf.createURI("urn:Dog"), properties);
+ restrictionsImplyingDog.put(vf.createURI("urn:Retriever"), properties);
+ Assert.assertEquals(restrictionsImplyingDog, inferenceEngine.getAllValuesFromByValueType(vf.createURI("urn:Dog")));
+ final Map<Resource, Set<URI>> restrictionsImplyingMammal = new HashMap<>(restrictionsImplyingDog);
+ restrictionsImplyingMammal.put(vf.createURI("urn:Person"), properties);
+ Assert.assertEquals(restrictionsImplyingMammal, inferenceEngine.getAllValuesFromByValueType(vf.createURI("urn:Mammal")));
+ }
+
+ @Test
public void testHasValueGivenProperty() throws Exception {
String insert = "INSERT DATA { GRAPH <http://updated/test> {\n"
+ " <urn:Biped> owl:onProperty <urn:walksUsingLegs> . \n"
http://git-wip-us.apache.org/repos/asf/incubator-rya/blob/2e88f105/sail/src/test/java/org/apache/rya/rdftriplestore/inference/InferenceIT.java
----------------------------------------------------------------------
diff --git a/sail/src/test/java/org/apache/rya/rdftriplestore/inference/InferenceIT.java b/sail/src/test/java/org/apache/rya/rdftriplestore/inference/InferenceIT.java
index c43c9e0..7d6f7d1 100644
--- a/sail/src/test/java/org/apache/rya/rdftriplestore/inference/InferenceIT.java
+++ b/sail/src/test/java/org/apache/rya/rdftriplestore/inference/InferenceIT.java
@@ -188,6 +188,43 @@ public class InferenceIT extends TestCase {
}
@Test
+ public void testAllValuesFromQuery() throws Exception {
+ final String ontology = "INSERT DATA { GRAPH <http://updated/test> {\n"
+ + " <urn:Cairn_Terrier> rdfs:subClassOf <urn:Terrier> .\n"
+ + " <urn:Terrier> rdfs:subClassOf <urn:Dog> ;\n"
+ + " owl:onProperty <urn:relative> ;\n"
+ + " owl:allValuesFrom <urn:Terrier> .\n"
+ + " <urn:Dog> rdfs:subClassOf [\n"
+ + " owl:onProperty <urn:portrays> ; owl:allValuesFrom <urn:FictionalDog>\n"
+ + " ] .\n"
+ + " <urn:parent> rdfs:subPropertyOf <urn:relative> .\n"
+ + "}}";
+ conn.prepareUpdate(QueryLanguage.SPARQL, ontology).execute();
+ inferenceEngine.refreshGraph();
+ final String instances = "INSERT DATA { GRAPH <http://updated/test> {\n"
+ + " <urn:Rommy> a <urn:Cairn_Terrier> .\n"
+ + " <urn:Rommy> <urn:parent> <urn:Terry> .\n"
+ + " <urn:Terry> <urn:portrays> <urn:Toto> .\n"
+ + "}}";
+ conn.prepareUpdate(QueryLanguage.SPARQL, instances).execute();
+ conn.prepareTupleQuery(QueryLanguage.SPARQL, "SELECT ?x { ?x a <urn:Dog> }").evaluate(resultHandler);
+ Assert.assertEquals(2, solutions.size());
+ Set<Value> answers = new HashSet<>();
+ for (BindingSet solution : solutions) {
+ answers.add(solution.getBinding("x").getValue());
+ }
+ Assert.assertTrue(answers.contains(vf.createURI("urn:Terry")));
+ Assert.assertTrue(answers.contains(vf.createURI("urn:Rommy")));
+ // If allValuesFrom inference were applied recursively, this triple wouldn't be needed:
+ conn.prepareUpdate(QueryLanguage.SPARQL, "INSERT DATA { GRAPH <http://updated/test> {\n"
+ + " <urn:Terry> a <urn:Cairn_Terrier> .\n"
+ + "}}").execute();
+ conn.prepareTupleQuery(QueryLanguage.SPARQL, "SELECT ?x { ?x a <urn:FictionalDog> }").evaluate(resultHandler);
+ Assert.assertEquals(1, solutions.size());
+ Assert.assertEquals(vf.createURI("urn:Toto"), solutions.get(0).getBinding("x").getValue());
+ }
+
+ @Test
public void testHasValueTypeQuery() throws Exception {
final String ontology = "INSERT DATA { GRAPH <http://updated/test> {\n"
+ " <urn:Biped> owl:onProperty <urn:walksOnLegs> ; owl:hasValue \"2\"^^<xsd:integer> . \n"