You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@rya.apache.org by pu...@apache.org on 2017/08/24 22:27:38 UTC
incubator-rya git commit: RYA-300 Added owl:oneOf inference. Closes
#215
Repository: incubator-rya
Updated Branches:
refs/heads/master e9488ff69 -> 8431dfb78
RYA-300 Added owl:oneOf inference. Closes #215
Project: http://git-wip-us.apache.org/repos/asf/incubator-rya/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-rya/commit/8431dfb7
Tree: http://git-wip-us.apache.org/repos/asf/incubator-rya/tree/8431dfb7
Diff: http://git-wip-us.apache.org/repos/asf/incubator-rya/diff/8431dfb7
Branch: refs/heads/master
Commit: 8431dfb783bed4e6e5d434ec5decccceccefffd1
Parents: e9488ff
Author: eric.white <Er...@parsons.com>
Authored: Wed Aug 23 11:08:58 2017 -0400
Committer: pujav65 <pu...@gmail.com>
Committed: Thu Aug 24 18:27:52 2017 -0400
----------------------------------------------------------------------
.../api/RdfCloudTripleStoreConfiguration.java | 20 +++
.../src/main/java/MongoRyaDirectExample.java | 105 +++++++++++
.../RdfCloudTripleStoreConnection.java | 2 +
.../inference/InferenceEngine.java | 76 ++++++++
.../rdftriplestore/inference/OneOfVisitor.java | 77 +++++++++
.../inference/InferenceEngineTest.java | 84 +++++++++
.../rdftriplestore/inference/InferenceIT.java | 99 ++++++++++-
.../inference/OneOfVisitorTest.java | 172 +++++++++++++++++++
8 files changed, 633 insertions(+), 2 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/incubator-rya/blob/8431dfb7/common/rya.api/src/main/java/org/apache/rya/api/RdfCloudTripleStoreConfiguration.java
----------------------------------------------------------------------
diff --git a/common/rya.api/src/main/java/org/apache/rya/api/RdfCloudTripleStoreConfiguration.java b/common/rya.api/src/main/java/org/apache/rya/api/RdfCloudTripleStoreConfiguration.java
index ee91e6b..eeb49b5 100644
--- a/common/rya.api/src/main/java/org/apache/rya/api/RdfCloudTripleStoreConfiguration.java
+++ b/common/rya.api/src/main/java/org/apache/rya/api/RdfCloudTripleStoreConfiguration.java
@@ -74,6 +74,7 @@ public abstract class RdfCloudTripleStoreConfiguration extends Configuration {
public static final String STATS_PUSH_EMPTY_RDFTYPE_DOWN = "conf.stats.rdftype.down";
public static final String INFER_INCLUDE_INTERSECTION_OF = "infer.include.intersectionof";
public static final String INFER_INCLUDE_INVERSEOF = "infer.include.inverseof";
+ public static final String INFER_INCLUDE_ONE_OF = "infer.include.oneof";
public static final String INFER_INCLUDE_SUBCLASSOF = "infer.include.subclassof";
public static final String INFER_INCLUDE_SUBPROPOF = "infer.include.subpropof";
public static final String INFER_INCLUDE_SYMMPROP = "infer.include.symmprop";
@@ -358,6 +359,25 @@ public abstract class RdfCloudTripleStoreConfiguration extends Configuration {
setBoolean(INFER_INCLUDE_INVERSEOF, val);
}
+ /**
+ * @return {@code true} if owl:oneOf inferencing is enabled.
+ * {@code false} otherwise. Defaults to {@code true} if nothing is
+ * specified.
+ */
+ public Boolean isInferOneOf() {
+ return getBoolean(INFER_INCLUDE_ONE_OF, true);
+ }
+
+ /**
+ * Sets whether owl:oneOf inferencing is enabled or disabled.
+ * @param value {@code true} if owl:oneOf inferencing is enabled.
+ * {@code false} otherwise.
+ */
+ public void setInferOneOf(final Boolean value) {
+ Preconditions.checkNotNull(value);
+ setBoolean(INFER_INCLUDE_ONE_OF, value);
+ }
+
public Boolean isInferSubClassOf() {
return getBoolean(INFER_INCLUDE_SUBCLASSOF, true);
}
http://git-wip-us.apache.org/repos/asf/incubator-rya/blob/8431dfb7/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 342916a..a2611d0 100644
--- a/extras/indexingExample/src/main/java/MongoRyaDirectExample.java
+++ b/extras/indexingExample/src/main/java/MongoRyaDirectExample.java
@@ -120,6 +120,7 @@ public class MongoRyaDirectExample {
testPropertyChainInferenceAltRepresentation(conn, sail);
testAllValuesFromInference(conn, sail);
testIntersectionOfInference(conn, sail);
+ testOneOfInference(conn, sail);
}
log.info("TIME: " + (System.currentTimeMillis() - start) / 1000.);
@@ -572,6 +573,110 @@ public class MongoRyaDirectExample {
Validate.isTrue(resultHandler.getCount() == 2);
}
+ public static void testOneOfInference(final SailRepositoryConnection conn, final Sail sail) throws MalformedQueryException, RepositoryException, UpdateExecutionException, QueryEvaluationException, TupleQueryResultHandlerException, InferenceEngineException {
+ log.info("Adding Data");
+ final String instances = "INSERT DATA"
+ + "{ GRAPH <http://updated/test> {\n"
+ + " <urn:FlopCard1> a <urn:Card> . \n"
+ + " <urn:FlopCard1> <urn:HasRank> <urn:Ace> . \n"
+ + " <urn:FlopCard1> <urn:HasSuit> <urn:Diamonds> . \n"
+ + " <urn:FlopCard2> a <urn:Card> . \n"
+ + " <urn:FlopCard2> <urn:HasRank> <urn:Ace> . \n"
+ + " <urn:FlopCard2> <urn:HasSuit> <urn:Hearts> . \n"
+ + " <urn:FlopCard3> a <urn:Card> . \n"
+ + " <urn:FlopCard3> <urn:HasRank> <urn:King> . \n"
+ + " <urn:FlopCard3> <urn:HasSuit> <urn:Spades> . \n"
+ + " <urn:TurnCard> a <urn:Card> . \n"
+ + " <urn:TurnCard> <urn:HasRank> <urn:10> . \n"
+ + " <urn:TurnCard> <urn:HasSuit> <urn:Clubs> . \n"
+ + " <urn:RiverCard> a <urn:Card> . \n"
+ + " <urn:RiverCard> <urn:HasRank> <urn:Queen> . \n"
+ + " <urn:RiverCard> <urn:HasSuit> <urn:Hearts> . \n"
+ + "}}";
+ Update update = conn.prepareUpdate(QueryLanguage.SPARQL, instances);
+ update.execute();
+ final String explicitQuery = "select distinct ?card { GRAPH <http://updated/test> {\n"
+ + " ?card a <urn:Card> . \n"
+ + " VALUES ?suit { <urn:Clubs> <urn:Diamonds> <urn:Hearts> <urn:Spades> } . \n"
+ + " ?card <urn:HasSuit> ?suit . \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() == 5);
+ log.info("Adding owl:oneOf Schema");
+ // ONTOLOGY - :Suits oneOf (:Clubs, :Diamonds, :Hearts, :Spades)
+ // ONTOLOGY - :Ranks oneOf (:Ace, :1, :2, :3, :4, :5, :6, :7, :8, :9, :10, :Jack, :Queen, :King)
+ final String ontology = "INSERT DATA { GRAPH <http://updated/test> {\n"
+ + " <urn:Suits> owl:oneOf _:bnodeS1 . \n"
+ + " _:bnodeS1 rdf:first <urn:Clubs> . \n"
+ + " _:bnodeS1 rdf:rest _:bnodeS2 . \n"
+ + " _:bnodeS2 rdf:first <urn:Diamonds> . \n"
+ + " _:bnodeS2 rdf:rest _:bnodeS3 . \n"
+ + " _:bnodeS3 rdf:first <urn:Hearts> . \n"
+ + " _:bnodeS3 rdf:rest _:bnodeS4 . \n"
+ + " _:bnodeS4 rdf:first <urn:Spades> . \n"
+ + " _:bnodeS4 rdf:rest rdf:nil . \n"
+ + " <urn:Ranks> owl:oneOf _:bnodeR1 . \n"
+ + " _:bnodeR1 rdf:first <urn:Ace> . \n"
+ + " _:bnodeR1 rdf:rest _:bnodeR2 . \n"
+ + " _:bnodeR2 rdf:first <urn:2> . \n"
+ + " _:bnodeR2 rdf:rest _:bnodeR3 . \n"
+ + " _:bnodeR3 rdf:first <urn:3> . \n"
+ + " _:bnodeR3 rdf:rest _:bnodeR4 . \n"
+ + " _:bnodeR4 rdf:first <urn:4> . \n"
+ + " _:bnodeR4 rdf:rest _:bnodeR5 . \n"
+ + " _:bnodeR5 rdf:first <urn:5> . \n"
+ + " _:bnodeR5 rdf:rest _:bnodeR6 . \n"
+ + " _:bnodeR6 rdf:first <urn:6> . \n"
+ + " _:bnodeR6 rdf:rest _:bnodeR7 . \n"
+ + " _:bnodeR7 rdf:first <urn:7> . \n"
+ + " _:bnodeR7 rdf:rest _:bnodeR8 . \n"
+ + " _:bnodeR8 rdf:first <urn:8> . \n"
+ + " _:bnodeR8 rdf:rest _:bnodeR9 . \n"
+ + " _:bnodeR9 rdf:first <urn:9> . \n"
+ + " _:bnodeR9 rdf:rest _:bnodeR10 . \n"
+ + " _:bnodeR10 rdf:first <urn:10> . \n"
+ + " _:bnodeR10 rdf:rest _:bnodeR11 . \n"
+ + " _:bnodeR11 rdf:first <urn:Jack> . \n"
+ + " _:bnodeR11 rdf:rest _:bnodeR12 . \n"
+ + " _:bnodeR12 rdf:first <urn:Queen> . \n"
+ + " _:bnodeR12 rdf:rest _:bnodeR13 . \n"
+ + " _:bnodeR13 rdf:first <urn:King> . \n"
+ + " _:bnodeR13 rdf:rest rdf:nil . \n"
+ + " <urn:Card> owl:intersectionOf (\n"
+ + " [ owl:onProperty <urn:HasRank> ; owl:someValuesFrom <urn:Ranks> ]\n"
+ + " [ owl:onProperty <urn:HasSuit> ; owl:someValuesFrom <urn:Suits> ]\n"
+ + " ) . \n"
+ + " <urn:HasRank> owl:range <urn:Ranks> . \n"
+ + " <urn:HasSuit> owl:range <urn:Suits> . \n"
+ + "}}";
+ update = conn.prepareUpdate(QueryLanguage.SPARQL, ontology);
+ update.execute();
+ log.info("Running Inference-dependent Query without refreshing InferenceEngine");
+ resultHandler.resetCount();
+ final String inferQuery = "select distinct ?card { GRAPH <http://updated/test> {\n"
+ + " ?card a <urn:Card> . \n"
+ + " ?suit a <urn:Suits> . \n"
+ + " ?card <urn:HasSuit> ?suit . \n"
+ + "}}";
+ tupleQuery = conn.prepareTupleQuery(QueryLanguage.SPARQL, inferQuery);
+ tupleQuery.evaluate(resultHandler);
+ log.info("Result count : " + resultHandler.getCount());
+ Validate.isTrue(resultHandler.getCount() == 0);
+ log.info("Refreshing InferenceEngine");
+ ((RdfCloudTripleStore) sail).getInferenceEngine().refreshGraph();
+ log.info("Re-running Inference-dependent Query");
+ resultHandler.resetCount();
+ resultHandler = new CountingResultHandler();
+ tupleQuery = conn.prepareTupleQuery(QueryLanguage.SPARQL, inferQuery);
+ tupleQuery.evaluate(resultHandler);
+ log.info("Result count : " + resultHandler.getCount());
+ Validate.isTrue(resultHandler.getCount() == 5);
+ }
+
public static void testInfer(final SailRepositoryConnection conn, final Sail sail) throws MalformedQueryException, RepositoryException,
UpdateExecutionException, QueryEvaluationException, TupleQueryResultHandlerException, InferenceEngineException {
http://git-wip-us.apache.org/repos/asf/incubator-rya/blob/8431dfb7/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 a64c0ec..dee5c8d 100644
--- a/sail/src/main/java/org/apache/rya/rdftriplestore/RdfCloudTripleStoreConnection.java
+++ b/sail/src/main/java/org/apache/rya/rdftriplestore/RdfCloudTripleStoreConnection.java
@@ -57,6 +57,7 @@ import org.apache.rya.rdftriplestore.inference.HasValueVisitor;
import org.apache.rya.rdftriplestore.inference.InferenceEngine;
import org.apache.rya.rdftriplestore.inference.IntersectionOfVisitor;
import org.apache.rya.rdftriplestore.inference.InverseOfVisitor;
+import org.apache.rya.rdftriplestore.inference.OneOfVisitor;
import org.apache.rya.rdftriplestore.inference.PropertyChainVisitor;
import org.apache.rya.rdftriplestore.inference.SameAsVisitor;
import org.apache.rya.rdftriplestore.inference.SubClassOfVisitor;
@@ -362,6 +363,7 @@ public class RdfCloudTripleStoreConnection extends SailConnectionBase {
tupleExpr.visit(new SubPropertyOfVisitor(queryConf, inferenceEngine));
tupleExpr.visit(new SubClassOfVisitor(queryConf, inferenceEngine));
tupleExpr.visit(new SameAsVisitor(queryConf, inferenceEngine));
+ tupleExpr.visit(new OneOfVisitor(queryConf, inferenceEngine));
} catch (final Exception e) {
logger.error("Error encountered while visiting query node.", e);
}
http://git-wip-us.apache.org/repos/asf/incubator-rya/blob/8431dfb7/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 a2f8d63..936fd41 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
@@ -85,6 +85,7 @@ public class InferenceEngine {
private Map<URI, Map<Resource, Value>> hasValueByProperty;
private Map<Resource, Map<Resource, URI>> allValuesFromByValueType;
private final ConcurrentHashMap<Resource, List<Set<Resource>>> intersections = new ConcurrentHashMap<>();
+ private final ConcurrentHashMap<Resource, Set<Resource>> enumerations = new ConcurrentHashMap<>();
private RyaDAO<?> ryaDAO;
private RdfCloudTripleStoreConfiguration conf;
@@ -203,6 +204,8 @@ public class InferenceEngine {
refreshIntersectionOf();
+ refreshOneOf();
+
iter = RyaDAOHelper.query(ryaDAO, null, RDF.TYPE, OWL.SYMMETRICPROPERTY, conf);
final Set<URI> symProp = new HashSet<>();
try {
@@ -761,6 +764,46 @@ public class InferenceEngine {
}
}
+ private void refreshOneOf() throws QueryEvaluationException {
+ final Map<Resource, Set<Resource>> enumTypes = new HashMap<>();
+
+ // First query for all the owl:oneOf's.
+ // If we have the following oneOf:
+ // :A owl:oneOf (:B, :C)
+ // It will be represented by triples following a pattern similar to:
+ // <:A> owl:oneOf _:bnode1 .
+ // _:bnode1 rdf:first <:B> .
+ // _:bnode1 rdf:rest _:bnode2 .
+ // _:bnode2 rdf:first <:C> .
+ // _:bnode2 rdf:rest rdf:nil .
+ ryaDaoQueryWrapper.queryAll(null, OWL.ONEOF, null, new RDFHandlerBase() {
+ @Override
+ public void handleStatement(final Statement statement) throws RDFHandlerException {
+ final Resource enumType = statement.getSubject();
+ // listHead will point to a type class of the enumeration.
+ final URI listHead = (URI) statement.getObject();
+ if (!enumTypes.containsKey(enumType)) {
+ enumTypes.put(enumType, new LinkedHashSet<Resource>());
+ }
+
+ // listHead should point to a list of items that forms the
+ // enumeration.
+ try {
+ final Set<Resource> enumeration = new LinkedHashSet<>(getList(listHead));
+ if (!enumeration.isEmpty()) {
+ // Add this enumeration for this type.
+ enumTypes.get(enumType).addAll(enumeration);
+ }
+ } catch (final QueryEvaluationException e) {
+ throw new RDFHandlerException("Error getting enumeration list.", e);
+ }
+ }
+ });
+
+ enumerations.clear();
+ enumerations.putAll(enumTypes);
+ }
+
/**
* Queries for all items that are in a list of the form:
* <pre>
@@ -1281,4 +1324,37 @@ public class InferenceEngine {
}
return null;
}
+
+ /**
+ * For a given type, return all sets of types such that owl:oneOf
+ * restrictions on those properties could imply this type. A enumeration
+ * of all the types that are part of the specified class type.
+ * @param type The type (URI or bnode) to check against the known oneOf
+ * sets.
+ * @return A {@link Set} of {@link Resource} types that represents the
+ * enumeration of resources that belong to the class type.
+ * An empty set is returned if no enumerations were found for the specified
+ * type.
+ */
+ public Set<Resource> getEnumeration(final Resource type) {
+ if (enumerations != null) {
+ final Set<Resource> oneOfSet = enumerations.get(type);
+ if (oneOfSet != null) {
+ return oneOfSet;
+ }
+ }
+ return new LinkedHashSet<>();
+
+ }
+
+ /**
+ * Checks if the specified type is an enumerated type.
+ * @param type The type (URI or bnode) to check against the known oneOf
+ * sets.
+ * @return {@code true} if the type is an enumerated type. {@code false}
+ * otherwise.
+ */
+ public boolean isEnumeratedType(final Resource type) {
+ return enumerations != null && enumerations.containsKey(type);
+ }
}
http://git-wip-us.apache.org/repos/asf/incubator-rya/blob/8431dfb7/sail/src/main/java/org/apache/rya/rdftriplestore/inference/OneOfVisitor.java
----------------------------------------------------------------------
diff --git a/sail/src/main/java/org/apache/rya/rdftriplestore/inference/OneOfVisitor.java b/sail/src/main/java/org/apache/rya/rdftriplestore/inference/OneOfVisitor.java
new file mode 100644
index 0000000..004a4b0
--- /dev/null
+++ b/sail/src/main/java/org/apache/rya/rdftriplestore/inference/OneOfVisitor.java
@@ -0,0 +1,77 @@
+/*
+ * 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.
+ */
+package org.apache.rya.rdftriplestore.inference;
+
+import java.util.LinkedHashSet;
+import java.util.Set;
+
+import org.apache.log4j.Logger;
+import org.apache.rya.api.RdfCloudTripleStoreConfiguration;
+import org.openrdf.model.Resource;
+import org.openrdf.model.vocabulary.RDF;
+import org.openrdf.query.BindingSet;
+import org.openrdf.query.algebra.BindingSetAssignment;
+import org.openrdf.query.algebra.StatementPattern;
+import org.openrdf.query.algebra.Var;
+import org.openrdf.query.algebra.evaluation.QueryBindingSet;
+
+/**
+ * Visitor for handling owl:oneOf inferencing on a node.
+ */
+public class OneOfVisitor extends AbstractInferVisitor {
+ private static final Logger log = Logger.getLogger(OneOfVisitor.class);
+
+ /**
+ * Creates a new instance of {@link OneOfVisitor}.
+ * @param conf the {@link RdfCloudeTripleStoreConfiguration}.
+ * @param inferenceEngine the {@link InferenceEngine}.
+ */
+ public OneOfVisitor(final RdfCloudTripleStoreConfiguration conf, final InferenceEngine inferenceEngine) {
+ super(conf, inferenceEngine);
+ include = conf.isInferOneOf();
+ }
+
+ @Override
+ protected void meetSP(final StatementPattern node) throws Exception {
+ final Var subVar = node.getSubjectVar();
+ final Var predVar = node.getPredicateVar();
+ final Var objVar = node.getObjectVar();
+ final Var conVar = node.getContextVar();
+ if (predVar != null && objVar != null && objVar.getValue() != null && objVar.getValue() instanceof Resource && RDF.TYPE.equals(predVar.getValue()) && !EXPANDED.equals(conVar)) {
+ final Resource object = (Resource) objVar.getValue();
+ if (inferenceEngine.isEnumeratedType(object)) {
+ final Set<BindingSet> solutions = new LinkedHashSet<>();
+ final Set<Resource> enumeration = inferenceEngine.getEnumeration(object);
+ for (final Resource enumType : enumeration) {
+ final QueryBindingSet qbs = new QueryBindingSet();
+ qbs.addBinding(subVar.getName(), enumType);
+ solutions.add(qbs);
+ }
+
+ if (!solutions.isEmpty()) {
+ final BindingSetAssignment enumNode = new BindingSetAssignment();
+ enumNode.setBindingSets(solutions);
+
+ node.replaceWith(enumNode);
+ log.trace("Replacing node with inferred one of enumeration: " + enumNode);
+ }
+ }
+ }
+ }
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/incubator-rya/blob/8431dfb7/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 10edf49..f290324 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
@@ -438,4 +438,88 @@ public class InferenceEngineTest extends TestCase {
Assert.assertTrue(momSuperClassUris.contains(mother));
Assert.assertTrue(momSuperClassUris.contains(mom));
}
+
+ @Test
+ public void testOneOf() throws Exception {
+ final String ontology = "INSERT DATA { GRAPH <http://updated/test> {\n"
+ + " <urn:Suits> owl:oneOf _:bnodeS1 . \n"
+ + " _:bnodeS1 rdf:first <urn:Clubs> . \n"
+ + " _:bnodeS1 rdf:rest _:bnodeS2 . \n"
+ + " _:bnodeS2 rdf:first <urn:Diamonds> . \n"
+ + " _:bnodeS2 rdf:rest _:bnodeS3 . \n"
+ + " _:bnodeS3 rdf:first <urn:Hearts> . \n"
+ + " _:bnodeS3 rdf:rest _:bnodeS4 . \n"
+ + " _:bnodeS4 rdf:first <urn:Spades> . \n"
+ + " _:bnodeS4 rdf:rest rdf:nil . \n"
+ + " <urn:Ranks> owl:oneOf _:bnodeR1 . \n"
+ + " _:bnodeR1 rdf:first <urn:Ace> . \n"
+ + " _:bnodeR1 rdf:rest _:bnodeR2 . \n"
+ + " _:bnodeR2 rdf:first <urn:2> . \n"
+ + " _:bnodeR2 rdf:rest _:bnodeR3 . \n"
+ + " _:bnodeR3 rdf:first <urn:3> . \n"
+ + " _:bnodeR3 rdf:rest _:bnodeR4 . \n"
+ + " _:bnodeR4 rdf:first <urn:4> . \n"
+ + " _:bnodeR4 rdf:rest _:bnodeR5 . \n"
+ + " _:bnodeR5 rdf:first <urn:5> . \n"
+ + " _:bnodeR5 rdf:rest _:bnodeR6 . \n"
+ + " _:bnodeR6 rdf:first <urn:6> . \n"
+ + " _:bnodeR6 rdf:rest _:bnodeR7 . \n"
+ + " _:bnodeR7 rdf:first <urn:7> . \n"
+ + " _:bnodeR7 rdf:rest _:bnodeR8 . \n"
+ + " _:bnodeR8 rdf:first <urn:8> . \n"
+ + " _:bnodeR8 rdf:rest _:bnodeR9 . \n"
+ + " _:bnodeR9 rdf:first <urn:9> . \n"
+ + " _:bnodeR9 rdf:rest _:bnodeR10 . \n"
+ + " _:bnodeR10 rdf:first <urn:10> . \n"
+ + " _:bnodeR10 rdf:rest _:bnodeR11 . \n"
+ + " _:bnodeR11 rdf:first <urn:Jack> . \n"
+ + " _:bnodeR11 rdf:rest _:bnodeR12 . \n"
+ + " _:bnodeR12 rdf:first <urn:Queen> . \n"
+ + " _:bnodeR12 rdf:rest _:bnodeR13 . \n"
+ + " _:bnodeR13 rdf:first <urn:King> . \n"
+ + " _:bnodeR13 rdf:rest rdf:nil . \n"
+ + "}}";
+
+ conn.prepareUpdate(QueryLanguage.SPARQL, ontology).execute();
+ inferenceEngine.refreshGraph();
+
+ final URI suits = vf.createURI("urn:Suits");
+ final URI ranks = vf.createURI("urn:Ranks");
+
+ final URI clubs = vf.createURI("urn:Clubs");
+ final URI diamonds = vf.createURI("urn:Diamonds");
+ final URI hearts = vf.createURI("urn:Hearts");
+ final URI spades = vf.createURI("urn:Spades");
+
+ final URI ace = vf.createURI("urn:Ace");
+ final URI two = vf.createURI("urn:2");
+ final URI three = vf.createURI("urn:3");
+ final URI four = vf.createURI("urn:4");
+ final URI five = vf.createURI("urn:5");
+ final URI six = vf.createURI("urn:6");
+ final URI seven = vf.createURI("urn:7");
+ final URI eight = vf.createURI("urn:8");
+ final URI nine = vf.createURI("urn:9");
+ final URI ten = vf.createURI("urn:10");
+ final URI jack = vf.createURI("urn:Jack");
+ final URI queen = vf.createURI("urn:Queen");
+ final URI king = vf.createURI("urn:King");
+
+ final URI joker = vf.createURI("urn:Joker");
+
+ final boolean isJokerEnumeratedType = inferenceEngine.isEnumeratedType(joker);
+ Assert.assertFalse(isJokerEnumeratedType);
+
+ final boolean isSuitsEnumeratedType = inferenceEngine.isEnumeratedType(suits);
+ Assert.assertTrue(isSuitsEnumeratedType);
+ final Set<Resource> enumerationImplyingSuits = Sets.newHashSet(clubs, diamonds, hearts, spades);
+ final Set<Resource> actualCardSuits = inferenceEngine.getEnumeration(suits);
+ Assert.assertEquals(enumerationImplyingSuits, actualCardSuits);
+
+ final boolean isRanksEnumeratedType = inferenceEngine.isEnumeratedType(ranks);
+ Assert.assertTrue(isRanksEnumeratedType);
+ final Set<Resource> enumerationImplyingRanks = Sets.newHashSet(ace, two, three, four, five, six, seven, eight, nine, ten, jack, queen, king);
+ final Set<Resource> actualCardRanks = inferenceEngine.getEnumeration(ranks);
+ Assert.assertEquals(enumerationImplyingRanks, actualCardRanks);
+ }
}
http://git-wip-us.apache.org/repos/asf/incubator-rya/blob/8431dfb7/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 dcda8a9..1fcfa2c 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
@@ -212,8 +212,8 @@ public class InferenceIT extends TestCase {
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) {
+ final Set<Value> answers = new HashSet<>();
+ for (final BindingSet solution : solutions) {
answers.add(solution.getBinding("x").getValue());
}
Assert.assertTrue(answers.contains(vf.createURI("urn:Terry")));
@@ -400,4 +400,99 @@ public class InferenceIT extends TestCase {
expectedMen.add(new ListBindingSet(varNames, vf.createURI("urn:Bob")));
Assert.assertEquals(expectedMen, new HashSet<>(solutions));
}
+
+ @Test
+ public void testOneOfQuery() throws Exception {
+ final String ontology = "INSERT DATA { GRAPH <http://updated/test> {\n"
+ + " <urn:Suits> owl:oneOf _:bnodeS1 . \n"
+ + " _:bnodeS1 rdf:first <urn:Clubs> . \n"
+ + " _:bnodeS1 rdf:rest _:bnodeS2 . \n"
+ + " _:bnodeS2 rdf:first <urn:Diamonds> . \n"
+ + " _:bnodeS2 rdf:rest _:bnodeS3 . \n"
+ + " _:bnodeS3 rdf:first <urn:Hearts> . \n"
+ + " _:bnodeS3 rdf:rest _:bnodeS4 . \n"
+ + " _:bnodeS4 rdf:first <urn:Spades> . \n"
+ + " _:bnodeS4 rdf:rest rdf:nil . \n"
+ + " <urn:Ranks> owl:oneOf _:bnodeR1 . \n"
+ + " _:bnodeR1 rdf:first <urn:Ace> . \n"
+ + " _:bnodeR1 rdf:rest _:bnodeR2 . \n"
+ + " _:bnodeR2 rdf:first <urn:2> . \n"
+ + " _:bnodeR2 rdf:rest _:bnodeR3 . \n"
+ + " _:bnodeR3 rdf:first <urn:3> . \n"
+ + " _:bnodeR3 rdf:rest _:bnodeR4 . \n"
+ + " _:bnodeR4 rdf:first <urn:4> . \n"
+ + " _:bnodeR4 rdf:rest _:bnodeR5 . \n"
+ + " _:bnodeR5 rdf:first <urn:5> . \n"
+ + " _:bnodeR5 rdf:rest _:bnodeR6 . \n"
+ + " _:bnodeR6 rdf:first <urn:6> . \n"
+ + " _:bnodeR6 rdf:rest _:bnodeR7 . \n"
+ + " _:bnodeR7 rdf:first <urn:7> . \n"
+ + " _:bnodeR7 rdf:rest _:bnodeR8 . \n"
+ + " _:bnodeR8 rdf:first <urn:8> . \n"
+ + " _:bnodeR8 rdf:rest _:bnodeR9 . \n"
+ + " _:bnodeR9 rdf:first <urn:9> . \n"
+ + " _:bnodeR9 rdf:rest _:bnodeR10 . \n"
+ + " _:bnodeR10 rdf:first <urn:10> . \n"
+ + " _:bnodeR10 rdf:rest _:bnodeR11 . \n"
+ + " _:bnodeR11 rdf:first <urn:Jack> . \n"
+ + " _:bnodeR11 rdf:rest _:bnodeR12 . \n"
+ + " _:bnodeR12 rdf:first <urn:Queen> . \n"
+ + " _:bnodeR12 rdf:rest _:bnodeR13 . \n"
+ + " _:bnodeR13 rdf:first <urn:King> . \n"
+ + " _:bnodeR13 rdf:rest rdf:nil . \n"
+ + " <urn:Card> owl:intersectionOf (\n"
+ + " [ owl:onProperty <urn:HasRank> ; owl:someValuesFrom <urn:Ranks> ]\n"
+ + " [ owl:onProperty <urn:HasSuit> ; owl:someValuesFrom <urn:Suits> ]\n"
+ + " ) . \n"
+ + " <urn:HasRank> owl:range <urn:Ranks> . \n"
+ + " <urn:HasSuit> owl:range <urn:Suits> . \n"
+ + "}}";
+ final String instances = "INSERT DATA { GRAPH <http://updated/test> {\n"
+ + " <urn:FlopCard1> a <urn:Card> . \n"
+ + " <urn:FlopCard1> <urn:HasRank> <urn:Ace> . \n"
+ + " <urn:FlopCard1> <urn:HasSuit> <urn:Diamonds> . \n"
+ + " <urn:FlopCard2> a <urn:Card> . \n"
+ + " <urn:FlopCard2> <urn:HasRank> <urn:Ace> . \n"
+ + " <urn:FlopCard2> <urn:HasSuit> <urn:Hearts> . \n"
+ + " <urn:FlopCard3> a <urn:Card> . \n"
+ + " <urn:FlopCard3> <urn:HasRank> <urn:King> . \n"
+ + " <urn:FlopCard3> <urn:HasSuit> <urn:Spades> . \n"
+ + " <urn:TurnCard> a <urn:Card> . \n"
+ + " <urn:TurnCard> <urn:HasRank> <urn:10> . \n"
+ + " <urn:TurnCard> <urn:HasSuit> <urn:Clubs> . \n"
+ + " <urn:RiverCard> a <urn:Card> . \n"
+ + " <urn:RiverCard> <urn:HasRank> <urn:Queen> . \n"
+ + " <urn:RiverCard> <urn:HasSuit> <urn:Hearts> . \n"
+ + "}}";
+ conn.prepareUpdate(QueryLanguage.SPARQL, ontology).execute();
+ conn.prepareUpdate(QueryLanguage.SPARQL, instances).execute();
+ inferenceEngine.refreshGraph();
+
+ final List<String> varNames = new LinkedList<>();
+ varNames.add("card");
+
+ // Find all cards with a <urn:Suits> type (expect 5 results)
+ final String cardSuitQuery = "SELECT ?card { GRAPH <http://updated/test> { ?card a <urn:Card> . ?suit a <urn:Suits> . ?card <urn:HasSuit> ?suit} } \n";
+ conn.prepareTupleQuery(QueryLanguage.SPARQL, cardSuitQuery).evaluate(resultHandler);
+ final Set<BindingSet> expectedCardSuits = new HashSet<>();
+ expectedCardSuits.add(new ListBindingSet(varNames, vf.createURI("urn:FlopCard1")));
+ expectedCardSuits.add(new ListBindingSet(varNames, vf.createURI("urn:FlopCard2")));
+ expectedCardSuits.add(new ListBindingSet(varNames, vf.createURI("urn:FlopCard3")));
+ expectedCardSuits.add(new ListBindingSet(varNames, vf.createURI("urn:TurnCard")));
+ expectedCardSuits.add(new ListBindingSet(varNames, vf.createURI("urn:RiverCard")));
+ Assert.assertEquals(expectedCardSuits.size(), solutions.size());
+ Assert.assertEquals(expectedCardSuits, new HashSet<>(solutions));
+
+ // Find all cards with a <urn:Ranks> type (expect 5 results)
+ final String cardRankQuery = "SELECT ?card { GRAPH <http://updated/test> { ?card a <urn:Card> . ?rank a <urn:Ranks> . ?card <urn:HasRank> ?rank} } \n";
+ conn.prepareTupleQuery(QueryLanguage.SPARQL, cardRankQuery).evaluate(resultHandler);
+ final Set<BindingSet> expectedCardRanks = new HashSet<>();
+ expectedCardRanks.add(new ListBindingSet(varNames, vf.createURI("urn:FlopCard1")));
+ expectedCardRanks.add(new ListBindingSet(varNames, vf.createURI("urn:FlopCard2")));
+ expectedCardRanks.add(new ListBindingSet(varNames, vf.createURI("urn:FlopCard3")));
+ expectedCardRanks.add(new ListBindingSet(varNames, vf.createURI("urn:TurnCard")));
+ expectedCardRanks.add(new ListBindingSet(varNames, vf.createURI("urn:RiverCard")));
+ Assert.assertEquals(expectedCardRanks.size(), solutions.size());
+ Assert.assertEquals(expectedCardRanks, new HashSet<>(solutions));
+ }
}
http://git-wip-us.apache.org/repos/asf/incubator-rya/blob/8431dfb7/sail/src/test/java/org/apache/rya/rdftriplestore/inference/OneOfVisitorTest.java
----------------------------------------------------------------------
diff --git a/sail/src/test/java/org/apache/rya/rdftriplestore/inference/OneOfVisitorTest.java b/sail/src/test/java/org/apache/rya/rdftriplestore/inference/OneOfVisitorTest.java
new file mode 100644
index 0000000..484c8bc
--- /dev/null
+++ b/sail/src/test/java/org/apache/rya/rdftriplestore/inference/OneOfVisitorTest.java
@@ -0,0 +1,172 @@
+/*
+ * 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.
+ */
+package org.apache.rya.rdftriplestore.inference;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+import java.util.Iterator;
+import java.util.Set;
+
+import org.apache.rya.accumulo.AccumuloRdfConfiguration;
+import org.junit.Test;
+import org.openrdf.model.Resource;
+import org.openrdf.model.URI;
+import org.openrdf.model.Value;
+import org.openrdf.model.ValueFactory;
+import org.openrdf.model.impl.ValueFactoryImpl;
+import org.openrdf.model.vocabulary.RDF;
+import org.openrdf.query.Binding;
+import org.openrdf.query.BindingSet;
+import org.openrdf.query.algebra.BindingSetAssignment;
+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.Var;
+import org.openrdf.query.algebra.evaluation.QueryBindingSet;
+
+import com.beust.jcommander.internal.Lists;
+import com.google.common.collect.Sets;
+
+/**
+ * Tests the methods of {@link OneOfVisitor}.
+ */
+public class OneOfVisitorTest {
+ private final AccumuloRdfConfiguration conf = new AccumuloRdfConfiguration();
+ private static final ValueFactory VF = new ValueFactoryImpl();
+
+ private static final URI SUITS = VF.createURI("urn:Suits");
+ private static final URI RANKS = VF.createURI("urn:Ranks");
+
+ // Definition #1: :Suits owl:oneOf(:Clubs, :Diamonds, :Hearts, :Spades)
+ private static final URI CLUBS = VF.createURI("urn:Clubs");
+ private static final URI DIAMONDS = VF.createURI("urn:Diamonds");
+ private static final URI HEARTS = VF.createURI("urn:Hearts");
+ private static final URI SPADES = VF.createURI("urn:Spades");
+
+ // Definition #2: :Ranks owl:oneOf(:Ace, :2, :3, :4, :5, :6, :7, :8, :9, :10, :Jack, :Queen, :King)
+ private static final URI ACE = VF.createURI("urn:Ace");
+ private static final URI TWO = VF.createURI("urn:2");
+ private static final URI THREE = VF.createURI("urn:3");
+ private static final URI FOUR = VF.createURI("urn:4");
+ private static final URI FIVE = VF.createURI("urn:5");
+ private static final URI SIX = VF.createURI("urn:6");
+ private static final URI SEVEN = VF.createURI("urn:7");
+ private static final URI EIGHT = VF.createURI("urn:8");
+ private static final URI NINE = VF.createURI("urn:9");
+ private static final URI TEN = VF.createURI("urn:10");
+ private static final URI JACK = VF.createURI("urn:Jack");
+ private static final URI QUEEN = VF.createURI("urn:Queen");
+ private static final URI KING = VF.createURI("urn:King");
+
+ private static final Set<Resource> CARD_SUIT_ENUMERATION =
+ Sets.newLinkedHashSet(
+ Lists.newArrayList(CLUBS, DIAMONDS, HEARTS, SPADES)
+ );
+ private static final Set<Resource> CARD_RANK_ENUMERATION =
+ Sets.newLinkedHashSet(
+ Lists.newArrayList(
+ ACE, TWO, THREE, FOUR, FIVE, SIX, SEVEN, EIGHT, NINE, TEN,
+ JACK, QUEEN, KING
+ )
+ );
+
+ @Test
+ public void testOneOf() throws Exception {
+ // Configure a mock instance engine with an ontology:
+ final InferenceEngine inferenceEngine = mock(InferenceEngine.class);
+ when(inferenceEngine.isEnumeratedType(SUITS)).thenReturn(true);
+ when(inferenceEngine.getEnumeration(SUITS)).thenReturn(CARD_SUIT_ENUMERATION);
+ when(inferenceEngine.isEnumeratedType(RANKS)).thenReturn(true);
+ when(inferenceEngine.getEnumeration(RANKS)).thenReturn(CARD_RANK_ENUMERATION);
+ // Query for a Suits and rewrite using the visitor:
+ final Projection query = new Projection(
+ new StatementPattern(new Var("s"), new Var("p", RDF.TYPE), new Var("o", SUITS)),
+ new ProjectionElemList(new ProjectionElem("s", "subject")));
+ query.visit(new OneOfVisitor(conf, inferenceEngine));
+ // Expected structure: BindingSetAssignment containing the enumeration:
+ // BindingSetAssignment(CLUBS, DIAMONDS, HEARTS, SPADES)
+ // Collect the arguments to the BindingSetAssignment:
+ assertTrue(query.getArg() instanceof BindingSetAssignment);
+ final BindingSetAssignment bsa = (BindingSetAssignment) query.getArg();
+ final Iterable<BindingSet> iterable = bsa.getBindingSets();
+ final Iterator<BindingSet> iter = iterable.iterator();
+
+ assertBindingSet(iter, CARD_SUIT_ENUMERATION.iterator());
+
+ // Query for a Ranks and rewrite using the visitor:
+ final Projection query2 = new Projection(
+ new StatementPattern(new Var("s"), new Var("p", RDF.TYPE), new Var("o", RANKS)),
+ new ProjectionElemList(new ProjectionElem("s", "subject")));
+ query2.visit(new OneOfVisitor(conf, inferenceEngine));
+ // Expected structure: BindingSetAssignment containing the enumeration:
+ // BindingSetAssignment(ACE, 2, 3, 4, 5, 6, 7, 8, 9, 10, JACK, QUEEN, KING)
+ // Collect the arguments to the BindingSetAssignment:
+ assertTrue(query2.getArg() instanceof BindingSetAssignment);
+ final BindingSetAssignment bsa2 = (BindingSetAssignment) query2.getArg();
+ final Iterable<BindingSet> iterable2 = bsa2.getBindingSets();
+ final Iterator<BindingSet> iter2 = iterable2.iterator();
+
+ assertBindingSet(iter2, CARD_RANK_ENUMERATION.iterator());
+ }
+
+ @Test
+ public void testOneOfDisabled() throws Exception {
+ // Configure a mock instance engine with an ontology:
+ final InferenceEngine inferenceEngine = mock(InferenceEngine.class);
+ when(inferenceEngine.isEnumeratedType(SUITS)).thenReturn(true);
+ when(inferenceEngine.getEnumeration(SUITS)).thenReturn(CARD_SUIT_ENUMERATION);
+ when(inferenceEngine.isEnumeratedType(RANKS)).thenReturn(true);
+ when(inferenceEngine.getEnumeration(RANKS)).thenReturn(CARD_RANK_ENUMERATION);
+
+ // Query for a Suits and rewrite using the visitor:
+ final Projection query = new Projection(
+ new StatementPattern(new Var("s"), new Var("p", RDF.TYPE), new Var("o", SUITS)),
+ new ProjectionElemList(new ProjectionElem("s", "subject")));
+
+ final AccumuloRdfConfiguration disabledConf = conf.clone();
+ disabledConf.setInferOneOf(false);
+
+ query.visit(new OneOfVisitor(disabledConf, inferenceEngine));
+
+ // Expected structure: the original statement:
+ assertTrue(query.getArg() instanceof StatementPattern);
+ final StatementPattern actualCardSuitSp = (StatementPattern) query.getArg();
+ final StatementPattern expectedCardSuitSp = new StatementPattern(new Var("s"), new Var("p", RDF.TYPE), new Var("o", SUITS));
+ assertEquals(expectedCardSuitSp, actualCardSuitSp);
+ }
+
+ private static void assertBindingSet(final Iterator<BindingSet> bindingSetIter, final Iterator<Resource> expectedValues) {
+ while (expectedValues.hasNext()) {
+ final Resource expectedValue = expectedValues.next();
+ assertTrue(bindingSetIter.hasNext());
+ final BindingSet bindingSet = bindingSetIter.next();
+ assertTrue(bindingSet instanceof QueryBindingSet);
+ assertEquals(1, bindingSet.getBindingNames().size());
+ final Binding binding = bindingSet.getBinding("s");
+ assertNotNull(binding);
+ final Value actualValue = binding.getValue();
+ assertEquals(expectedValue, actualValue);
+ }
+ }
+}
\ No newline at end of file