diff --git a/shacl/pom.xml b/shacl/pom.xml index 688944a3d..0d1d741c0 100644 --- a/shacl/pom.xml +++ b/shacl/pom.xml @@ -70,6 +70,12 @@ logback-classic test + + ${project.groupId} + rdf4j-sail-nativerdf + ${project.version} + test + diff --git a/shacl/src/main/java/org/eclipse/rdf4j/sail/shacl/AST/ClassPropertyShape.java b/shacl/src/main/java/org/eclipse/rdf4j/sail/shacl/AST/ClassPropertyShape.java index d86a1038b..7bf1c1981 100644 --- a/shacl/src/main/java/org/eclipse/rdf4j/sail/shacl/AST/ClassPropertyShape.java +++ b/shacl/src/main/java/org/eclipse/rdf4j/sail/shacl/AST/ClassPropertyShape.java @@ -18,21 +18,19 @@ import org.eclipse.rdf4j.sail.SailConnection; import org.eclipse.rdf4j.sail.shacl.ShaclSailConnection; import org.eclipse.rdf4j.sail.shacl.SourceConstraintComponent; -import org.eclipse.rdf4j.sail.shacl.planNodes.BufferedSplitter; -import org.eclipse.rdf4j.sail.shacl.planNodes.BufferedTupleFromFilter; +import org.eclipse.rdf4j.sail.shacl.planNodes.BufferedPlanNode; import org.eclipse.rdf4j.sail.shacl.planNodes.BulkedExternalInnerJoin; import org.eclipse.rdf4j.sail.shacl.planNodes.BulkedExternalLeftOuterJoin; -import org.eclipse.rdf4j.sail.shacl.planNodes.DirectTupleFromFilter; import org.eclipse.rdf4j.sail.shacl.planNodes.EnrichWithShape; import org.eclipse.rdf4j.sail.shacl.planNodes.ExternalTypeFilterNode; import org.eclipse.rdf4j.sail.shacl.planNodes.InnerJoin; import org.eclipse.rdf4j.sail.shacl.planNodes.LoggingNode; import org.eclipse.rdf4j.sail.shacl.planNodes.ModifyTuple; import org.eclipse.rdf4j.sail.shacl.planNodes.PlanNode; -import org.eclipse.rdf4j.sail.shacl.planNodes.PushBasedLoggingNode; import org.eclipse.rdf4j.sail.shacl.planNodes.Select; import org.eclipse.rdf4j.sail.shacl.planNodes.Sort; import org.eclipse.rdf4j.sail.shacl.planNodes.TupleLengthFilter; +import org.eclipse.rdf4j.sail.shacl.planNodes.UnBufferedPlanNode; import org.eclipse.rdf4j.sail.shacl.planNodes.UnionNode; import org.eclipse.rdf4j.sail.shacl.planNodes.Unique; import org.slf4j.Logger; @@ -79,33 +77,25 @@ public PlanNode getPlan(ShaclSailConnection shaclSailConnection, NodeShape nodeS return new EnrichWithShape(invalidTuplesDueToDataAddedThatMatchesTargetOrPath, this); } else { - PlanNode addedByShape1 = new LoggingNode(nodeShape.getPlanAddedStatements(shaclSailConnection, nodeShape), ""); - - - BufferedSplitter bufferedAddedByShape = new BufferedSplitter(addedByShape1); PlanNode addedByPath = new LoggingNode(getPlanAddedStatements(shaclSailConnection, nodeShape), ""); - - BufferedTupleFromFilter discardedRight = new BufferedTupleFromFilter(); - // join all added by type and path - PlanNode leftOuterJoin = new LoggingNode(new InnerJoin(bufferedAddedByShape.getPlanNode(), addedByPath, null,new PushBasedLoggingNode(discardedRight)), ""); + InnerJoin innerJoinHolder = new InnerJoin(new LoggingNode(nodeShape.getPlanAddedStatements(shaclSailConnection, nodeShape), ""), addedByPath); + PlanNode innerJoin = new LoggingNode(innerJoinHolder.getJoined(BufferedPlanNode.class), ""); + PlanNode discardedRight = new LoggingNode(innerJoinHolder.getDiscardedRight(BufferedPlanNode.class), ""); - if (nodeShape instanceof TargetClass) { - PlanNode typeFilterPlan = new LoggingNode(((TargetClass) nodeShape).getTypeFilterPlan(shaclSailConnection, discardedRight), ""); + PlanNode typeFilterPlan = new LoggingNode(nodeShape.getTargetFilter(shaclSailConnection, discardedRight), ""); - leftOuterJoin = new LoggingNode(new Unique(new UnionNode(leftOuterJoin, typeFilterPlan)), ""); + innerJoin = new LoggingNode(new Unique(new UnionNode(innerJoin, typeFilterPlan)), ""); - } // also add anything that matches the path from the previousConnection, eg. if you add ":peter a foaf:Person", and ":peter foaf:knows :steve" is already added - PlanNode bulkedExternalLeftOuter = new LoggingNode(new BulkedExternalLeftOuterJoin(bufferedAddedByShape.getPlanNode(), shaclSailConnection, path.getQuery("?a", "?c", null), true), ""); + PlanNode bulkedExternalLeftOuter = new LoggingNode(new BulkedExternalLeftOuterJoin(new LoggingNode(nodeShape.getPlanAddedStatements(shaclSailConnection, nodeShape), ""), shaclSailConnection, path.getQuery("?a", "?c", null), true), ""); - // only get tuples that came from the first or the leftOuterJoin or bulkedExternalLeftOuter, + // only get tuples that came from the first or the innerJoin or bulkedExternalLeftOuter, // we don't care if you added ":peter a foaf:Person" and nothing else and there is nothing else in the underlying sail - DirectTupleFromFilter joined = new DirectTupleFromFilter(); - new TupleLengthFilter(new UnionNode(leftOuterJoin, bulkedExternalLeftOuter), joined, null, 2, false); + PlanNode joined = new TupleLengthFilter(new UnionNode(innerJoin, bulkedExternalLeftOuter), 2, false).getTrueNode(UnBufferedPlanNode.class); // filter by type against addedStatements, this is an optimization for when you add the type statement in the same transaction PlanNode addedStatementsTypeFilter = new LoggingNode(new ExternalTypeFilterNode(addedStatements, classResource, joined, 1, false), ""); @@ -113,7 +103,7 @@ public PlanNode getPlan(ShaclSailConnection shaclSailConnection, NodeShape nodeS // filter by type against the base sail PlanNode invalidTuplesDueToDataAddedThatMatchesTargetOrPath = new LoggingNode(new ExternalTypeFilterNode(shaclSailConnection, classResource, addedStatementsTypeFilter, 1, false), ""); - if(shaclSailConnection.stats.hasRemoved()) { + if (shaclSailConnection.stats.hasRemoved()) { // Handle when a type statement has been removed, first get all removed type statements that match the classResource for this shape PlanNode removedTypeStatements = new LoggingNode(new Select(shaclSailConnection.getRemovedStatements(), "?a a <" + classResource + ">"), "removedTypeStatements"); diff --git a/shacl/src/main/java/org/eclipse/rdf4j/sail/shacl/AST/DatatypePropertyShape.java b/shacl/src/main/java/org/eclipse/rdf4j/sail/shacl/AST/DatatypePropertyShape.java index 4575c66f1..afa4cd65a 100644 --- a/shacl/src/main/java/org/eclipse/rdf4j/sail/shacl/AST/DatatypePropertyShape.java +++ b/shacl/src/main/java/org/eclipse/rdf4j/sail/shacl/AST/DatatypePropertyShape.java @@ -40,7 +40,7 @@ public PlanNode getPlan(ShaclSailConnection shaclSailConnection, NodeShape nodeS PlanNode invalidValues = StandardisedPlanHelper.getGenericSingleObjectPlan( shaclSailConnection, nodeShape, - (parent, trueNode, falseNode) -> new DatatypeFilter(parent, trueNode, falseNode, datatype), + (parent) -> new DatatypeFilter(parent, datatype), this, overrideTargetNode ); diff --git a/shacl/src/main/java/org/eclipse/rdf4j/sail/shacl/AST/LanguageInPropertyShape.java b/shacl/src/main/java/org/eclipse/rdf4j/sail/shacl/AST/LanguageInPropertyShape.java index 9055d2cbe..58d02ad02 100644 --- a/shacl/src/main/java/org/eclipse/rdf4j/sail/shacl/AST/LanguageInPropertyShape.java +++ b/shacl/src/main/java/org/eclipse/rdf4j/sail/shacl/AST/LanguageInPropertyShape.java @@ -43,7 +43,7 @@ public PlanNode getPlan(ShaclSailConnection shaclSailConnection, NodeShape nodeS PlanNode invalidValues = StandardisedPlanHelper.getGenericSingleObjectPlan( shaclSailConnection, nodeShape, - (parent, trueNode, falseNode) -> new LanguageInFilter(parent, trueNode, falseNode, languageIn), + (parent) -> new LanguageInFilter(parent, languageIn), this, overrideTargetNode); diff --git a/shacl/src/main/java/org/eclipse/rdf4j/sail/shacl/AST/MaxCountPropertyShape.java b/shacl/src/main/java/org/eclipse/rdf4j/sail/shacl/AST/MaxCountPropertyShape.java index 86af1740b..f26a2e349 100644 --- a/shacl/src/main/java/org/eclipse/rdf4j/sail/shacl/AST/MaxCountPropertyShape.java +++ b/shacl/src/main/java/org/eclipse/rdf4j/sail/shacl/AST/MaxCountPropertyShape.java @@ -13,15 +13,15 @@ import org.eclipse.rdf4j.repository.sail.SailRepositoryConnection; import org.eclipse.rdf4j.sail.shacl.ShaclSailConnection; import org.eclipse.rdf4j.sail.shacl.SourceConstraintComponent; -import org.eclipse.rdf4j.sail.shacl.planNodes.BufferedTupleFromFilter; +import org.eclipse.rdf4j.sail.shacl.planNodes.BufferedPlanNode; import org.eclipse.rdf4j.sail.shacl.planNodes.BulkedExternalLeftOuterJoin; -import org.eclipse.rdf4j.sail.shacl.planNodes.DirectTupleFromFilter; import org.eclipse.rdf4j.sail.shacl.planNodes.EnrichWithShape; import org.eclipse.rdf4j.sail.shacl.planNodes.GroupByCount; import org.eclipse.rdf4j.sail.shacl.planNodes.LoggingNode; import org.eclipse.rdf4j.sail.shacl.planNodes.MaxCountFilter; import org.eclipse.rdf4j.sail.shacl.planNodes.PlanNode; import org.eclipse.rdf4j.sail.shacl.planNodes.TrimTuple; +import org.eclipse.rdf4j.sail.shacl.planNodes.UnBufferedPlanNode; import org.eclipse.rdf4j.sail.shacl.planNodes.UnionNode; import org.eclipse.rdf4j.sail.shacl.planNodes.Unique; import org.slf4j.Logger; @@ -53,15 +53,13 @@ public String toString() { @Override public PlanNode getPlan(ShaclSailConnection shaclSailConnection, NodeShape nodeShape, boolean printPlans, PlanNode overrideTargetNode) { - if(overrideTargetNode != null){ + if (overrideTargetNode != null) { PlanNode bulkedExternalLeftOuterJoin = new LoggingNode(new BulkedExternalLeftOuterJoin(overrideTargetNode, shaclSailConnection, path.getQuery("?a", "?c", null), false), ""); PlanNode groupByCount = new LoggingNode(new GroupByCount(bulkedExternalLeftOuterJoin), ""); - DirectTupleFromFilter directTupleFromFilter = new DirectTupleFromFilter(); + PlanNode directTupleFromFilter = new LoggingNode(new MaxCountFilter(groupByCount, maxCount).getFalseNode(UnBufferedPlanNode.class), ""); - new MaxCountFilter(groupByCount, null, directTupleFromFilter, maxCount); - - if(printPlans){ + if (printPlans) { String planAsGraphvizDot = getPlanAsGraphvizDot(directTupleFromFilter, shaclSailConnection); logger.info(planAsGraphvizDot); } @@ -74,19 +72,17 @@ public PlanNode getPlan(ShaclSailConnection shaclSailConnection, NodeShape nodeS PlanNode planAddedStatements1 = new LoggingNode(super.getPlanAddedStatements(shaclSailConnection, nodeShape), ""); - - if (nodeShape instanceof TargetClass) { - planAddedStatements1 = new LoggingNode(((TargetClass) nodeShape).getTypeFilterPlan(shaclSailConnection, planAddedStatements1), ""); - } + planAddedStatements1 = new LoggingNode(nodeShape.getTargetFilter(shaclSailConnection, planAddedStatements1), ""); PlanNode mergeNode = new LoggingNode(new UnionNode(planAddedStatements, planAddedStatements1), ""); PlanNode groupByCount1 = new LoggingNode(new GroupByCount(mergeNode), ""); - BufferedTupleFromFilter validValues = new BufferedTupleFromFilter(); - BufferedTupleFromFilter invalidValues = new BufferedTupleFromFilter(); - new MaxCountFilter(groupByCount1, validValues, invalidValues, maxCount); + MaxCountFilter maxCountFilter = new MaxCountFilter(groupByCount1, maxCount); + + PlanNode validValues = maxCountFilter.getTrueNode(BufferedPlanNode.class); + PlanNode invalidValues = maxCountFilter.getFalseNode(BufferedPlanNode.class); PlanNode trimmed = new LoggingNode(new TrimTuple(validValues, 0, 1), ""); @@ -96,13 +92,11 @@ public PlanNode getPlan(ShaclSailConnection shaclSailConnection, NodeShape nodeS PlanNode groupByCount = new LoggingNode(new GroupByCount(bulkedExternalLeftOuterJoin), ""); - DirectTupleFromFilter directTupleFromFilter = new DirectTupleFromFilter(); - - new MaxCountFilter(groupByCount, null, directTupleFromFilter, maxCount); + PlanNode directTupleFromFilter = new MaxCountFilter(groupByCount, maxCount).getFalseNode(UnBufferedPlanNode.class); PlanNode mergeNode1 = new UnionNode(new LoggingNode(directTupleFromFilter, ""), new LoggingNode(invalidValues, "")); - if(printPlans){ + if (printPlans) { String planAsGraphvizDot = getPlanAsGraphvizDot(mergeNode1, shaclSailConnection); logger.info(planAsGraphvizDot); } diff --git a/shacl/src/main/java/org/eclipse/rdf4j/sail/shacl/AST/MaxExclusivePropertyShape.java b/shacl/src/main/java/org/eclipse/rdf4j/sail/shacl/AST/MaxExclusivePropertyShape.java index 567fe5e90..dc8c6ccad 100644 --- a/shacl/src/main/java/org/eclipse/rdf4j/sail/shacl/AST/MaxExclusivePropertyShape.java +++ b/shacl/src/main/java/org/eclipse/rdf4j/sail/shacl/AST/MaxExclusivePropertyShape.java @@ -42,7 +42,7 @@ public PlanNode getPlan(ShaclSailConnection shaclSailConnection, NodeShape nodeS PlanNode invalidValues = StandardisedPlanHelper.getGenericSingleObjectPlan( shaclSailConnection, nodeShape, - (parent, trueNode, falseNode) -> new LiteralComparatorFilter(parent, trueNode, falseNode, maxExclusive, value -> value > 0), + (parent) -> new LiteralComparatorFilter(parent, maxExclusive, value -> value > 0), this, overrideTargetNode); diff --git a/shacl/src/main/java/org/eclipse/rdf4j/sail/shacl/AST/MaxInclusivePropertyShape.java b/shacl/src/main/java/org/eclipse/rdf4j/sail/shacl/AST/MaxInclusivePropertyShape.java index 9fdb52ac9..6fd40d07d 100644 --- a/shacl/src/main/java/org/eclipse/rdf4j/sail/shacl/AST/MaxInclusivePropertyShape.java +++ b/shacl/src/main/java/org/eclipse/rdf4j/sail/shacl/AST/MaxInclusivePropertyShape.java @@ -42,7 +42,7 @@ public PlanNode getPlan(ShaclSailConnection shaclSailConnection, NodeShape nodeS PlanNode invalidValues = StandardisedPlanHelper.getGenericSingleObjectPlan( shaclSailConnection, nodeShape, - (parent, trueNode, falseNode) -> new LiteralComparatorFilter(parent, trueNode, falseNode, maxInclusive, value -> value >= 0), + (parent) -> new LiteralComparatorFilter(parent, maxInclusive, value -> value >= 0), this, overrideTargetNode); diff --git a/shacl/src/main/java/org/eclipse/rdf4j/sail/shacl/AST/MaxLengthPropertyShape.java b/shacl/src/main/java/org/eclipse/rdf4j/sail/shacl/AST/MaxLengthPropertyShape.java index b72659460..b88d64e05 100644 --- a/shacl/src/main/java/org/eclipse/rdf4j/sail/shacl/AST/MaxLengthPropertyShape.java +++ b/shacl/src/main/java/org/eclipse/rdf4j/sail/shacl/AST/MaxLengthPropertyShape.java @@ -40,7 +40,7 @@ public PlanNode getPlan(ShaclSailConnection shaclSailConnection, NodeShape nodeS PlanNode invalidValues = StandardisedPlanHelper.getGenericSingleObjectPlan( shaclSailConnection, nodeShape, - (parent, trueNode, falseNode) -> new MaxLengthFilter(parent, trueNode, falseNode, maxLength), + (parent) -> new MaxLengthFilter(parent, maxLength), this, overrideTargetNode); diff --git a/shacl/src/main/java/org/eclipse/rdf4j/sail/shacl/AST/MinCountPropertyShape.java b/shacl/src/main/java/org/eclipse/rdf4j/sail/shacl/AST/MinCountPropertyShape.java index 40a966227..d61355f45 100644 --- a/shacl/src/main/java/org/eclipse/rdf4j/sail/shacl/AST/MinCountPropertyShape.java +++ b/shacl/src/main/java/org/eclipse/rdf4j/sail/shacl/AST/MinCountPropertyShape.java @@ -14,14 +14,13 @@ import org.eclipse.rdf4j.sail.shacl.ShaclSailConnection; import org.eclipse.rdf4j.sail.shacl.SourceConstraintComponent; import org.eclipse.rdf4j.sail.shacl.planNodes.BulkedExternalLeftOuterJoin; -import org.eclipse.rdf4j.sail.shacl.planNodes.DirectTupleFromFilter; import org.eclipse.rdf4j.sail.shacl.planNodes.EnrichWithShape; import org.eclipse.rdf4j.sail.shacl.planNodes.GroupByCount; import org.eclipse.rdf4j.sail.shacl.planNodes.LoggingNode; import org.eclipse.rdf4j.sail.shacl.planNodes.MinCountFilter; import org.eclipse.rdf4j.sail.shacl.planNodes.PlanNode; -import org.eclipse.rdf4j.sail.shacl.planNodes.Select; import org.eclipse.rdf4j.sail.shacl.planNodes.TrimTuple; +import org.eclipse.rdf4j.sail.shacl.planNodes.UnBufferedPlanNode; import org.eclipse.rdf4j.sail.shacl.planNodes.UnionNode; import org.eclipse.rdf4j.sail.shacl.planNodes.Unique; import org.slf4j.Logger; @@ -56,12 +55,11 @@ public String toString() { @Override public PlanNode getPlan(ShaclSailConnection shaclSailConnection, NodeShape nodeShape, boolean printPlans, PlanNode overrideTargetNode) { - if(overrideTargetNode != null){ + if (overrideTargetNode != null) { PlanNode allStatements = new LoggingNode(new BulkedExternalLeftOuterJoin(overrideTargetNode, shaclSailConnection, path.getQuery("?a", "?c", null), false), ""); PlanNode groupBy = new LoggingNode(new GroupByCount(allStatements), ""); - DirectTupleFromFilter filteredStatements = new DirectTupleFromFilter(); - new MinCountFilter(groupBy, null, filteredStatements, minCount); + PlanNode filteredStatements = new MinCountFilter(groupBy, minCount).getFalseNode(UnBufferedPlanNode.class); if (printPlans) { String planAsGraphvizDot = getPlanAsGraphvizDot(filteredStatements, shaclSailConnection); @@ -77,11 +75,7 @@ public PlanNode getPlan(ShaclSailConnection shaclSailConnection, NodeShape nodeS if (!optimizeWhenNoStatementsRemoved || shaclSailConnection.stats.hasRemoved()) { PlanNode planRemovedStatements = new LoggingNode(new TrimTuple(new LoggingNode(super.getPlanRemovedStatements(shaclSailConnection, nodeShape), ""), 0, 1), ""); - PlanNode filteredPlanRemovedStatements = planRemovedStatements; - - if (nodeShape instanceof TargetClass) { - filteredPlanRemovedStatements = new LoggingNode(((TargetClass) nodeShape).getTypeFilterPlan(shaclSailConnection, planRemovedStatements), ""); - } + PlanNode filteredPlanRemovedStatements = new LoggingNode(nodeShape.getTargetFilter(shaclSailConnection, planRemovedStatements), ""); PlanNode planAddedStatements = new LoggingNode(nodeShape.getPlanAddedStatements(shaclSailConnection, nodeShape), ""); @@ -92,9 +86,8 @@ public PlanNode getPlan(ShaclSailConnection shaclSailConnection, NodeShape nodeS PlanNode planAddedStatements1 = super.getPlanAddedStatements(shaclSailConnection, nodeShape); - if (nodeShape instanceof TargetClass) { - planAddedStatements1 = new LoggingNode(((TargetClass) nodeShape).getTypeFilterPlan(shaclSailConnection, planAddedStatements1), ""); - } + planAddedStatements1 = new LoggingNode((nodeShape).getTargetFilter(shaclSailConnection, planAddedStatements1), ""); + topNode = new LoggingNode(new UnionNode(unique, planAddedStatements1), ""); @@ -106,21 +99,18 @@ public PlanNode getPlan(ShaclSailConnection shaclSailConnection, NodeShape nodeS PlanNode planAddedForShape = new LoggingNode(nodeShape.getPlanAddedStatements(shaclSailConnection, nodeShape), ""); - PlanNode select = new LoggingNode(shaclSailConnection.getCachedNodeFor(new Select(shaclSailConnection.getAddedStatements(), path.getQuery("?a", "?c", null))), ""); + PlanNode addedByPath = new LoggingNode(getPlanAddedStatements(shaclSailConnection, nodeShape), ""); + addedByPath = new LoggingNode((nodeShape).getTargetFilter(shaclSailConnection, addedByPath), ""); - if (nodeShape instanceof TargetClass) { - select = new LoggingNode(((TargetClass) nodeShape).getTypeFilterPlan(shaclSailConnection, select), ""); - } - topNode = new LoggingNode(new UnionNode(planAddedForShape, select), ""); + topNode = new LoggingNode(new UnionNode(planAddedForShape, addedByPath), ""); } PlanNode groupBy = new LoggingNode(new GroupByCount(topNode), ""); - DirectTupleFromFilter filteredStatements = new DirectTupleFromFilter(); - new MinCountFilter(groupBy, null, filteredStatements, minCount); + PlanNode filteredStatements = new MinCountFilter(groupBy, minCount).getFalseNode(UnBufferedPlanNode.class); PlanNode minCountFilter = new LoggingNode(filteredStatements, ""); @@ -130,8 +120,7 @@ public PlanNode getPlan(ShaclSailConnection shaclSailConnection, NodeShape nodeS PlanNode groupBy2 = new LoggingNode(new GroupByCount(bulkedExternalLeftOuterJoin2), ""); - DirectTupleFromFilter filteredStatements2 = new DirectTupleFromFilter(); - new MinCountFilter(groupBy2, null, filteredStatements2, minCount); + PlanNode filteredStatements2 = new MinCountFilter(groupBy2, minCount).getFalseNode(UnBufferedPlanNode.class); if (printPlans) { String planAsGraphvizDot = getPlanAsGraphvizDot(filteredStatements2, shaclSailConnection); diff --git a/shacl/src/main/java/org/eclipse/rdf4j/sail/shacl/AST/MinExclusivePropertyShape.java b/shacl/src/main/java/org/eclipse/rdf4j/sail/shacl/AST/MinExclusivePropertyShape.java index 0024126e6..452acb18a 100644 --- a/shacl/src/main/java/org/eclipse/rdf4j/sail/shacl/AST/MinExclusivePropertyShape.java +++ b/shacl/src/main/java/org/eclipse/rdf4j/sail/shacl/AST/MinExclusivePropertyShape.java @@ -42,7 +42,7 @@ public PlanNode getPlan(ShaclSailConnection shaclSailConnection, NodeShape nodeS PlanNode invalidValues = StandardisedPlanHelper.getGenericSingleObjectPlan( shaclSailConnection, nodeShape, - (parent, trueNode, falseNode) -> new LiteralComparatorFilter(parent, trueNode, falseNode, minExclusive, value -> value < 0), + (parent) -> new LiteralComparatorFilter(parent, minExclusive, value -> value < 0), this, overrideTargetNode); diff --git a/shacl/src/main/java/org/eclipse/rdf4j/sail/shacl/AST/MinInclusivePropertyShape.java b/shacl/src/main/java/org/eclipse/rdf4j/sail/shacl/AST/MinInclusivePropertyShape.java index c4d2eb709..c136f5129 100644 --- a/shacl/src/main/java/org/eclipse/rdf4j/sail/shacl/AST/MinInclusivePropertyShape.java +++ b/shacl/src/main/java/org/eclipse/rdf4j/sail/shacl/AST/MinInclusivePropertyShape.java @@ -41,7 +41,7 @@ public PlanNode getPlan(ShaclSailConnection shaclSailConnection, NodeShape nodeS PlanNode invalidValues = StandardisedPlanHelper.getGenericSingleObjectPlan( shaclSailConnection, nodeShape, - (parent, trueNode, falseNode) -> new LiteralComparatorFilter(parent, trueNode, falseNode, minInclusive, value -> value <= 0), + (parent) -> new LiteralComparatorFilter(parent, minInclusive, value -> value <= 0), this, overrideTargetNode); diff --git a/shacl/src/main/java/org/eclipse/rdf4j/sail/shacl/AST/MinLengthPropertyShape.java b/shacl/src/main/java/org/eclipse/rdf4j/sail/shacl/AST/MinLengthPropertyShape.java index 3062786a5..515142b17 100644 --- a/shacl/src/main/java/org/eclipse/rdf4j/sail/shacl/AST/MinLengthPropertyShape.java +++ b/shacl/src/main/java/org/eclipse/rdf4j/sail/shacl/AST/MinLengthPropertyShape.java @@ -40,7 +40,7 @@ public PlanNode getPlan(ShaclSailConnection shaclSailConnection, NodeShape nodeS PlanNode invalidValues = StandardisedPlanHelper.getGenericSingleObjectPlan( shaclSailConnection, nodeShape, - (parent, trueNode, falseNode) -> new MinLengthFilter(parent, trueNode, falseNode, minLength), + (parent) -> new MinLengthFilter(parent, minLength), this, overrideTargetNode); diff --git a/shacl/src/main/java/org/eclipse/rdf4j/sail/shacl/AST/NodeKindPropertyShape.java b/shacl/src/main/java/org/eclipse/rdf4j/sail/shacl/AST/NodeKindPropertyShape.java index 1221c2fb6..af06f712e 100644 --- a/shacl/src/main/java/org/eclipse/rdf4j/sail/shacl/AST/NodeKindPropertyShape.java +++ b/shacl/src/main/java/org/eclipse/rdf4j/sail/shacl/AST/NodeKindPropertyShape.java @@ -69,7 +69,7 @@ public PlanNode getPlan(ShaclSailConnection shaclSailConnection, NodeShape nodeS PlanNode invalidValues = StandardisedPlanHelper.getGenericSingleObjectPlan( shaclSailConnection, nodeShape, - (parent, trueNode, falseNode) -> new NodeKindFilter(parent, trueNode, falseNode, nodeKind), + (parent) -> new NodeKindFilter(parent, nodeKind), this, overrideTargetNode); diff --git a/shacl/src/main/java/org/eclipse/rdf4j/sail/shacl/AST/NodeShape.java b/shacl/src/main/java/org/eclipse/rdf4j/sail/shacl/AST/NodeShape.java index d34ab2df6..e378886f3 100644 --- a/shacl/src/main/java/org/eclipse/rdf4j/sail/shacl/AST/NodeShape.java +++ b/shacl/src/main/java/org/eclipse/rdf4j/sail/shacl/AST/NodeShape.java @@ -14,6 +14,7 @@ import org.eclipse.rdf4j.model.vocabulary.RDF; import org.eclipse.rdf4j.model.vocabulary.SHACL; import org.eclipse.rdf4j.repository.sail.SailRepositoryConnection; +import org.eclipse.rdf4j.sail.NotifyingSailConnection; import org.eclipse.rdf4j.sail.SailConnection; import org.eclipse.rdf4j.sail.shacl.RdfsSubClassOfReasoner; import org.eclipse.rdf4j.sail.shacl.ShaclSail; @@ -93,8 +94,13 @@ public static class Factory { public static List getShapes(SailRepositoryConnection connection, ShaclSail sail) { try (Stream stream = Iterations.stream(connection.getStatements(null, RDF.TYPE, SHACL.NODE_SHAPE))) { return stream.map(Statement::getSubject).map(shapeId -> { - if (hasTargetClass(shapeId, connection)) { - return new TargetClass(shapeId, connection); + + ShaclProperties shaclProperties = new ShaclProperties(shapeId, connection); + + if (shaclProperties.targetClass != null) { + return new TargetClass(shapeId, connection, shaclProperties.targetClass); + } else if (!shaclProperties.targetNode.isEmpty()) { + return new TargetNode(shapeId, connection, shaclProperties.targetNode); } else { if(sail.isUndefinedTargetValidatesAllSubjects()) { return new NodeShape(shapeId, connection); // target class nodeShapes are the only supported nodeShapes @@ -107,13 +113,14 @@ public static List getShapes(SailRepositoryConnection connection, Sha } } - private static boolean hasTargetClass(Resource shapeId, SailRepositoryConnection connection) { - return connection.hasStatement(shapeId, SHACL.TARGET_CLASS, null, true); } - } @Override public String toString() { return id.toString(); } + + public PlanNode getTargetFilter(NotifyingSailConnection shaclSailConnection, PlanNode parent) { + return parent; + } } diff --git a/shacl/src/main/java/org/eclipse/rdf4j/sail/shacl/AST/OrPropertyShape.java b/shacl/src/main/java/org/eclipse/rdf4j/sail/shacl/AST/OrPropertyShape.java index 79f55b1f7..a8dba3f71 100644 --- a/shacl/src/main/java/org/eclipse/rdf4j/sail/shacl/AST/OrPropertyShape.java +++ b/shacl/src/main/java/org/eclipse/rdf4j/sail/shacl/AST/OrPropertyShape.java @@ -13,6 +13,7 @@ import org.eclipse.rdf4j.sail.SailConnection; import org.eclipse.rdf4j.sail.shacl.ShaclSailConnection; import org.eclipse.rdf4j.sail.shacl.SourceConstraintComponent; +import org.eclipse.rdf4j.sail.shacl.planNodes.BufferedPlanNode; import org.eclipse.rdf4j.sail.shacl.planNodes.BufferedSplitter; import org.eclipse.rdf4j.sail.shacl.planNodes.EnrichWithShape; import org.eclipse.rdf4j.sail.shacl.planNodes.EqualsJoin; @@ -118,10 +119,10 @@ public PlanNode getPlan(ShaclSailConnection shaclSailConnection, NodeShape nodeS ret = new LoggingNode(equalsJoin, ""); } else if (iteratorData == IteratorData.aggregated) { - PlanNode innerJoin = new LoggingNode(new InnerJoin(unionAll(plannodes.get(0)), unionAll(plannodes.get(1)), null, null), ""); + PlanNode innerJoin = new LoggingNode(new InnerJoin(unionAll(plannodes.get(0)), unionAll(plannodes.get(1))).getJoined(BufferedPlanNode.class), ""); for (int i = 2; i < or.size(); i++) { - innerJoin = new LoggingNode(new InnerJoin(innerJoin, unionAll(plannodes.get(i)), null, null), ""); + innerJoin = new LoggingNode(new InnerJoin(innerJoin, unionAll(plannodes.get(i))).getJoined(BufferedPlanNode.class), ""); } ret = new LoggingNode(innerJoin, ""); diff --git a/shacl/src/main/java/org/eclipse/rdf4j/sail/shacl/AST/PatternPropertyShape.java b/shacl/src/main/java/org/eclipse/rdf4j/sail/shacl/AST/PatternPropertyShape.java index f8ca45a90..d63239172 100644 --- a/shacl/src/main/java/org/eclipse/rdf4j/sail/shacl/AST/PatternPropertyShape.java +++ b/shacl/src/main/java/org/eclipse/rdf4j/sail/shacl/AST/PatternPropertyShape.java @@ -52,7 +52,7 @@ public PlanNode getPlan(ShaclSailConnection shaclSailConnection, NodeShape nodeS PlanNode invalidValues = StandardisedPlanHelper.getGenericSingleObjectPlan( shaclSailConnection, nodeShape, - (parent, trueNode, falseNode) -> new PatternFilter(parent, trueNode, falseNode, pattern, flags), + (parent) -> new PatternFilter(parent, pattern, flags), this, overrideTargetNode); diff --git a/shacl/src/main/java/org/eclipse/rdf4j/sail/shacl/AST/ShaclProperties.java b/shacl/src/main/java/org/eclipse/rdf4j/sail/shacl/AST/ShaclProperties.java index 49b705ee2..c38048a31 100644 --- a/shacl/src/main/java/org/eclipse/rdf4j/sail/shacl/AST/ShaclProperties.java +++ b/shacl/src/main/java/org/eclipse/rdf4j/sail/shacl/AST/ShaclProperties.java @@ -7,6 +7,8 @@ import org.eclipse.rdf4j.model.Value; import org.eclipse.rdf4j.repository.sail.SailRepositoryConnection; +import java.util.ArrayList; +import java.util.List; import java.util.stream.Stream; public class ShaclProperties { @@ -32,6 +34,9 @@ public class ShaclProperties { String pattern; + Resource targetClass; + List targetNode = new ArrayList<>(0); + public ShaclProperties(Resource propertyShapeId, SailRepositoryConnection connection) { @@ -119,11 +124,20 @@ public ShaclProperties(Resource propertyShapeId, SailRepositoryConnection connec pattern = object.stringValue(); break; case "http://www.w3.org/ns/shacl#class": - if (pattern != null) { + if (clazz != null) { throw new IllegalStateException("sh:class aleady populated"); } clazz = (Resource) object; break; + case "http://www.w3.org/ns/shacl#targetNode": + targetNode.add(object); + break; + case "http://www.w3.org/ns/shacl#targetClass": + if (targetClass != null) { + throw new IllegalStateException("sh:targetClass aleady populated"); + } + targetClass = (Resource) object; + break; } diff --git a/shacl/src/main/java/org/eclipse/rdf4j/sail/shacl/AST/StandardisedPlanHelper.java b/shacl/src/main/java/org/eclipse/rdf4j/sail/shacl/AST/StandardisedPlanHelper.java index 48ba1baac..438d80955 100644 --- a/shacl/src/main/java/org/eclipse/rdf4j/sail/shacl/AST/StandardisedPlanHelper.java +++ b/shacl/src/main/java/org/eclipse/rdf4j/sail/shacl/AST/StandardisedPlanHelper.java @@ -1,67 +1,69 @@ +/******************************************************************************* + * Copyright (c) 2018 Eclipse RDF4J contributors. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Distribution License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/org/documents/edl-v10.php. + *******************************************************************************/ + package org.eclipse.rdf4j.sail.shacl.AST; import org.eclipse.rdf4j.sail.shacl.ShaclSailConnection; -import org.eclipse.rdf4j.sail.shacl.planNodes.BufferedSplitter; -import org.eclipse.rdf4j.sail.shacl.planNodes.BufferedTupleFromFilter; +import org.eclipse.rdf4j.sail.shacl.planNodes.BufferedPlanNode; import org.eclipse.rdf4j.sail.shacl.planNodes.BulkedExternalInnerJoin; -import org.eclipse.rdf4j.sail.shacl.planNodes.DirectTupleFromFilter; +import org.eclipse.rdf4j.sail.shacl.planNodes.FilterPlanNode; import org.eclipse.rdf4j.sail.shacl.planNodes.InnerJoin; import org.eclipse.rdf4j.sail.shacl.planNodes.LoggingNode; import org.eclipse.rdf4j.sail.shacl.planNodes.PlanNode; -import org.eclipse.rdf4j.sail.shacl.planNodes.PushBasedLoggingNode; -import org.eclipse.rdf4j.sail.shacl.planNodes.PushBasedPlanNode; -import org.eclipse.rdf4j.sail.shacl.planNodes.Select; +import org.eclipse.rdf4j.sail.shacl.planNodes.UnBufferedPlanNode; import org.eclipse.rdf4j.sail.shacl.planNodes.UnionNode; + public class StandardisedPlanHelper { interface FilterAttacher { - void attachFilter(PlanNode parent, PushBasedPlanNode trueNode, PushBasedPlanNode falseNode); + FilterPlanNode attachFilter(PlanNode parent); } static public PlanNode getGenericSingleObjectPlan(ShaclSailConnection shaclSailConnection, NodeShape nodeShape, FilterAttacher filterAttacher, PathPropertyShape pathPropertyShape, PlanNode overrideTargetNode) { if (overrideTargetNode != null) { PlanNode bulkedExternalInnerJoin = new LoggingNode(new BulkedExternalInnerJoin(overrideTargetNode, shaclSailConnection, pathPropertyShape.path.getQuery("?a", "?c", null), false), ""); - DirectTupleFromFilter invalidValues = new DirectTupleFromFilter(); - filterAttacher.attachFilter(bulkedExternalInnerJoin, null, new PushBasedLoggingNode(invalidValues)); - - return invalidValues; + return new LoggingNode(filterAttacher.attachFilter(bulkedExternalInnerJoin).getFalseNode(UnBufferedPlanNode.class), ""); } - PlanNode addedByShape = new LoggingNode(nodeShape.getPlanAddedStatements(shaclSailConnection, nodeShape), ""); + PlanNode addedByPath = new LoggingNode(pathPropertyShape.getPlanAddedStatements(shaclSailConnection, nodeShape), ""); - BufferedSplitter bufferedSplitter = new BufferedSplitter(addedByShape); + // this is essentially pushing the filter down below the join + PlanNode invalidValuesDirectOnPath = new LoggingNode(filterAttacher.attachFilter(addedByPath).getFalseNode(UnBufferedPlanNode.class), ""); - PlanNode addedByPath = new LoggingNode(shaclSailConnection.getCachedNodeFor(new Select(shaclSailConnection.getAddedStatements(), pathPropertyShape.path.getQuery("?a", "?c", null))), ""); - // this is essentially pushing the filter down below the join - DirectTupleFromFilter invalidValuesDirectOnPath = new DirectTupleFromFilter(); + InnerJoin innerJoin = new InnerJoin(new LoggingNode(nodeShape.getPlanAddedStatements(shaclSailConnection, nodeShape), ""), invalidValuesDirectOnPath); - filterAttacher.attachFilter(addedByPath, null, new PushBasedLoggingNode(invalidValuesDirectOnPath)); + if(shaclSailConnection.stats.isBaseSailEmpty()){ + return new LoggingNode(innerJoin.getJoined(UnBufferedPlanNode.class), ""); + }else { - BufferedTupleFromFilter discardedRight = new BufferedTupleFromFilter(); + PlanNode top = new LoggingNode(innerJoin.getJoined(BufferedPlanNode.class), ""); - PlanNode top = new LoggingNode(new InnerJoin(bufferedSplitter.getPlanNode(), invalidValuesDirectOnPath, null, new PushBasedLoggingNode(discardedRight)), ""); - if(!shaclSailConnection.stats.isBaseSailEmpty()) { - if (nodeShape instanceof TargetClass) { - PlanNode typeFilterPlan = new LoggingNode(((TargetClass) nodeShape).getTypeFilterPlan(shaclSailConnection, discardedRight), ""); + PlanNode discardedRight = innerJoin.getDiscardedRight(BufferedPlanNode.class); + + PlanNode typeFilterPlan = new LoggingNode(nodeShape.getTargetFilter(shaclSailConnection, discardedRight), ""); top = new LoggingNode(new UnionNode(top, typeFilterPlan), ""); - } - PlanNode bulkedExternalInnerJoin = new LoggingNode(new BulkedExternalInnerJoin(bufferedSplitter.getPlanNode(), shaclSailConnection, pathPropertyShape.path.getQuery("?a", "?c", null), true), ""); + + PlanNode bulkedExternalInnerJoin = new LoggingNode(new BulkedExternalInnerJoin(new LoggingNode(nodeShape.getPlanAddedStatements(shaclSailConnection, nodeShape), ""), shaclSailConnection, pathPropertyShape.path.getQuery("?a", "?c", null), true), ""); top = new LoggingNode(new UnionNode(top, bulkedExternalInnerJoin), ""); - } - DirectTupleFromFilter invalidValues = new DirectTupleFromFilter(); - filterAttacher.attachFilter(top, null, new PushBasedLoggingNode(invalidValues)); + return new LoggingNode(filterAttacher.attachFilter(top).getFalseNode(UnBufferedPlanNode.class), ""); + + } - return invalidValues; } diff --git a/shacl/src/main/java/org/eclipse/rdf4j/sail/shacl/AST/TargetClass.java b/shacl/src/main/java/org/eclipse/rdf4j/sail/shacl/AST/TargetClass.java index 161a37957..4d2aff924 100644 --- a/shacl/src/main/java/org/eclipse/rdf4j/sail/shacl/AST/TargetClass.java +++ b/shacl/src/main/java/org/eclipse/rdf4j/sail/shacl/AST/TargetClass.java @@ -28,37 +28,36 @@ import java.util.stream.Stream; /** - * The AST (Abstract Syntax Tree) node + * sh:targetClass * * @author Heshan Jayasinghe */ public class TargetClass extends NodeShape { - Resource targetClass; + private final Resource targetClass; - TargetClass(Resource id, SailRepositoryConnection connection) { + TargetClass(Resource id, SailRepositoryConnection connection, Resource targetClass) { super(id, connection); - - try (Stream stream = Iterations.stream(connection.getStatements(id, SHACL.TARGET_CLASS, null))) { - targetClass = stream.map(Statement::getObject).map(v -> (Resource) v).findAny().orElseThrow(() -> new RuntimeException("Expected to find sh:targetClass on " + id)); - } - + this.targetClass = targetClass; } @Override public PlanNode getPlan(ShaclSailConnection shaclSailConnection, NodeShape nodeShape, boolean printPlans, PlanNode overrideTargetNode) { - return new TrimTuple(new LoggingNode(new Select(shaclSailConnection, getQuery("?a", "?c", shaclSailConnection.getRdfsSubClassOfReasoner())), ""), 0, 1); + PlanNode parent = shaclSailConnection.getCachedNodeFor(new Select(shaclSailConnection, getQuery("?a", "?c", shaclSailConnection.getRdfsSubClassOfReasoner()))); + return new TrimTuple(new LoggingNode(parent, ""), 0, 1); } @Override public PlanNode getPlanAddedStatements(ShaclSailConnection shaclSailConnection, NodeShape nodeShape) { - return new TrimTuple(new LoggingNode(new Select(shaclSailConnection.getAddedStatements(), getQuery("?a", "?c", null)), ""), 0, 1); + PlanNode cachedNodeFor = shaclSailConnection.getCachedNodeFor(new Select(shaclSailConnection.getAddedStatements(), getQuery("?a", "?c", null))); + return new TrimTuple(new LoggingNode(cachedNodeFor, ""), 0, 1); } @Override public PlanNode getPlanRemovedStatements(ShaclSailConnection shaclSailConnection, NodeShape nodeShape) { - return new Select(shaclSailConnection.getRemovedStatements(), getQuery("?a", "?c", null)); + PlanNode parent = shaclSailConnection.getCachedNodeFor(new Select(shaclSailConnection.getRemovedStatements(), getQuery("?a", "?c", null))); + return new TrimTuple(parent, 0,1); } @Override @@ -82,7 +81,8 @@ public String getQuery(String subjectVariable, String objectVariable, RdfsSubCla return "BIND(rdf:type as ?b1) \n BIND(<" + targetClass + "> as "+objectVariable+") \n "+subjectVariable+" ?b1 "+objectVariable+". \n"; } - public PlanNode getTypeFilterPlan(NotifyingSailConnection shaclSailConnection, PlanNode parent) { + @Override + public PlanNode getTargetFilter(NotifyingSailConnection shaclSailConnection, PlanNode parent) { return new ExternalTypeFilterNode(shaclSailConnection, targetClass, parent, 0, true); } diff --git a/shacl/src/main/java/org/eclipse/rdf4j/sail/shacl/AST/TargetNode.java b/shacl/src/main/java/org/eclipse/rdf4j/sail/shacl/AST/TargetNode.java new file mode 100644 index 000000000..9c66e78c8 --- /dev/null +++ b/shacl/src/main/java/org/eclipse/rdf4j/sail/shacl/AST/TargetNode.java @@ -0,0 +1,82 @@ +/******************************************************************************* + * Copyright (c) 2018 Eclipse RDF4J contributors. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Distribution License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/org/documents/edl-v10.php. + *******************************************************************************/ + +package org.eclipse.rdf4j.sail.shacl.AST; + +import org.eclipse.rdf4j.model.Resource; +import org.eclipse.rdf4j.model.Value; +import org.eclipse.rdf4j.repository.sail.SailRepositoryConnection; +import org.eclipse.rdf4j.sail.NotifyingSailConnection; +import org.eclipse.rdf4j.sail.SailConnection; +import org.eclipse.rdf4j.sail.shacl.RdfsSubClassOfReasoner; +import org.eclipse.rdf4j.sail.shacl.ShaclSailConnection; +import org.eclipse.rdf4j.sail.shacl.planNodes.LoggingNode; +import org.eclipse.rdf4j.sail.shacl.planNodes.PlanNode; +import org.eclipse.rdf4j.sail.shacl.planNodes.Select; +import org.eclipse.rdf4j.sail.shacl.planNodes.SetFilterNode; +import org.eclipse.rdf4j.sail.shacl.planNodes.TrimTuple; + +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +/** + * sh:targetNode + * + * @author Håvard Ottestad + */ +public class TargetNode extends NodeShape { + + private final Set targetNodeSet; + + TargetNode(Resource id, SailRepositoryConnection connection, List targetNode) { + super(id, connection); + this.targetNodeSet = new HashSet<>(targetNode); + assert !this.targetNodeSet.isEmpty(); + } + + @Override + public PlanNode getPlan(ShaclSailConnection shaclSailConnection, NodeShape nodeShape, boolean printPlans, PlanNode overrideTargetNode) { + PlanNode parent = shaclSailConnection.getCachedNodeFor(new Select(shaclSailConnection, getQuery("?a", "?c", shaclSailConnection.getRdfsSubClassOfReasoner()))); + return new TrimTuple(new LoggingNode(parent, ""), 0, 1); + } + + @Override + public PlanNode getPlanAddedStatements(ShaclSailConnection shaclSailConnection, NodeShape nodeShape) { + PlanNode parent = shaclSailConnection.getCachedNodeFor(new Select(shaclSailConnection.getAddedStatements(), getQuery("?a", "?c", null))); + return new TrimTuple(new LoggingNode(parent, ""), 0, 1); + + } + + @Override + public PlanNode getPlanRemovedStatements(ShaclSailConnection shaclSailConnection, NodeShape nodeShape) { + PlanNode parent = shaclSailConnection.getCachedNodeFor(new Select(shaclSailConnection.getRemovedStatements(), getQuery("?a", "?c", null))); + return new TrimTuple(parent, 0, 1); + } + + @Override + public boolean requiresEvaluation(SailConnection addedStatements, SailConnection removedStatements) { + return true; + } + + @Override + public String getQuery(String subjectVariable, String objectVariable, RdfsSubClassOfReasoner rdfsSubClassOfReasoner) { + + return targetNodeSet.stream() + .map(r -> "{{ select * where {BIND(<" + r + "> as " + subjectVariable + "). " + subjectVariable + " ?b1 " + objectVariable + " .}}}") + .reduce((a, b) -> a + " UNION " + b) + .get(); + + } + + @Override + public PlanNode getTargetFilter(NotifyingSailConnection shaclSailConnection, PlanNode parent) { + return new LoggingNode(new SetFilterNode(targetNodeSet, parent, 0, true), "targetNode filter"); + } + +} diff --git a/shacl/src/main/java/org/eclipse/rdf4j/sail/shacl/NoShapesLoadedException.java b/shacl/src/main/java/org/eclipse/rdf4j/sail/shacl/NoShapesLoadedException.java index 33f99ca24..a6a2e13f1 100644 --- a/shacl/src/main/java/org/eclipse/rdf4j/sail/shacl/NoShapesLoadedException.java +++ b/shacl/src/main/java/org/eclipse/rdf4j/sail/shacl/NoShapesLoadedException.java @@ -1,3 +1,11 @@ +/******************************************************************************* + * Copyright (c) 2018 Eclipse RDF4J contributors. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Distribution License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/org/documents/edl-v10.php. + *******************************************************************************/ + package org.eclipse.rdf4j.sail.shacl; import org.eclipse.rdf4j.model.vocabulary.RDF4J; diff --git a/shacl/src/main/java/org/eclipse/rdf4j/sail/shacl/RdfsSubClassOfReasoner.java b/shacl/src/main/java/org/eclipse/rdf4j/sail/shacl/RdfsSubClassOfReasoner.java index b1dc80963..472cfe7ac 100644 --- a/shacl/src/main/java/org/eclipse/rdf4j/sail/shacl/RdfsSubClassOfReasoner.java +++ b/shacl/src/main/java/org/eclipse/rdf4j/sail/shacl/RdfsSubClassOfReasoner.java @@ -1,3 +1,11 @@ +/******************************************************************************* + * Copyright (c) 2018 Eclipse RDF4J contributors. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Distribution License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/org/documents/edl-v10.php. + *******************************************************************************/ + package org.eclipse.rdf4j.sail.shacl; import org.eclipse.rdf4j.common.iteration.Iterations; diff --git a/shacl/src/main/java/org/eclipse/rdf4j/sail/shacl/ShaclSail.java b/shacl/src/main/java/org/eclipse/rdf4j/sail/shacl/ShaclSail.java index 2fba2675c..86d8a6e90 100644 --- a/shacl/src/main/java/org/eclipse/rdf4j/sail/shacl/ShaclSail.java +++ b/shacl/src/main/java/org/eclipse/rdf4j/sail/shacl/ShaclSail.java @@ -25,6 +25,8 @@ import org.eclipse.rdf4j.sail.shacl.AST.NodeShape; import org.eclipse.rdf4j.sail.shacl.config.ShaclSailConfig; import org.eclipse.rdf4j.sail.shacl.planNodes.LoggingNode; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import java.io.File; import java.io.IOException; @@ -137,14 +139,13 @@ */ public class ShaclSail extends NotifyingSailWrapper { + private static final Logger logger = LoggerFactory.getLogger(ShaclSail.class); + private List nodeShapes = Collections.emptyList(); private static String SH_OR_UPDATE_QUERY; - private static String SH_OR_NODE_SHAPE_UPDATE_QUERY; - private static String IMPLICIT_TARGET_CLASS_NODE_SHAPE; - private static String IMPLICIT_TARGET_CLASS_PROPERTY_SHAPE; /** @@ -153,46 +154,32 @@ public class ShaclSail extends NotifyingSailWrapper { private SailRepository shapesRepo; private boolean parallelValidation = ShaclSailConfig.PARALLEL_VALIDATION_DEFAULT; - private boolean undefinedTargetValidatesAllSubjects = ShaclSailConfig.UNDEFINED_TARGET_VALIDATES_ALL_SUBJECTS_DEFAULT; - private boolean logValidationPlans = ShaclSailConfig.LOG_VALIDATION_PLANS_DEFAULT; - private boolean logValidationViolations = ShaclSailConfig.LOG_VALIDATION_VIOLATIONS_DEFAULT; - private boolean ignoreNoShapesLoadedException = ShaclSailConfig.IGNORE_NO_SHAPES_LOADED_EXCEPTION_DEFAULT; - private boolean validationEnabled = ShaclSailConfig.VALIDATION_ENABLED_DEFAULT; - private boolean cacheSelectNodes = ShaclSailConfig.CACHE_SELECT_NODES_DEFAULT; - private boolean rdfsSubClassReasoning = ShaclSailConfig.RDFS_SUB_CLASS_REASONING_DEFAULT; + private boolean initializing = false; + static { try { - SH_OR_UPDATE_QUERY = IOUtils.toString( - ShaclSail.class.getClassLoader().getResourceAsStream("shacl-sparql-inference/sh_or.rq"), - "UTF-8"); - SH_OR_NODE_SHAPE_UPDATE_QUERY = IOUtils.toString( - ShaclSail.class.getClassLoader().getResourceAsStream( - "shacl-sparql-inference/sh_or_node_shape.rq"), - "UTF-8"); - IMPLICIT_TARGET_CLASS_NODE_SHAPE = IOUtils.toString( - ShaclSail.class.getClassLoader().getResourceAsStream( - "shacl-sparql-inference/implicitTargetClassNodeShape.rq"), - "UTF-8"); - - IMPLICIT_TARGET_CLASS_PROPERTY_SHAPE = IOUtils.toString( - ShaclSail.class.getClassLoader().getResourceAsStream( - "shacl-sparql-inference/implicitTargetClassPropertyShape.rq"), - "UTF-8"); - } - catch (IOException e) { + SH_OR_UPDATE_QUERY = resourceAsString("shacl-sparql-inference/sh_or.rq"); + SH_OR_NODE_SHAPE_UPDATE_QUERY = resourceAsString("shacl-sparql-inference/sh_or_node_shape.rq"); + IMPLICIT_TARGET_CLASS_NODE_SHAPE = resourceAsString("shacl-sparql-inference/implicitTargetClassNodeShape.rq"); + IMPLICIT_TARGET_CLASS_PROPERTY_SHAPE = resourceAsString("shacl-sparql-inference/implicitTargetClassPropertyShape.rq"); + } catch (IOException e) { throw new IllegalStateException(e); } } + private static String resourceAsString(String s) throws IOException { + return IOUtils.toString(ShaclSail.class.getClassLoader().getResourceAsStream(s), "UTF-8"); + } + public ShaclSail(NotifyingSail baseSail) { super(baseSail); @@ -205,7 +192,7 @@ public ShaclSail() { /** * Lists the predicates that have been implemented in the ShaclSail. All of these, and all combinations, * should work, please report any bugs. For sh:path, only single predicate paths are supported. - * + * * @return List of IRIs (SHACL predicates) */ public static List getSupportedShaclPredicates() { @@ -227,14 +214,23 @@ public static List getSupportedShaclPredicates() { SHACL.MIN_INCLUSIVE, SHACL.MAX_EXCLUSIVE, SHACL.MAX_INCLUSIVE, - SHACL.CLASS + SHACL.CLASS, + SHACL.TARGET_NODE ); } @Override public void initialize() throws SailException { + initializing = true; super.initialize(); + if (getDataDir() != null) { + if(parallelValidation){ + logger.info("Automatically disabled parallel SHACL validation because persistent base sail was detected! Re-enable by calling setParallelValidation(true) after calling init() / initialize()."); + } + setParallelValidation(false); + } + if (shapesRepo != null) { shapesRepo.shutDown(); shapesRepo = null; @@ -248,32 +244,33 @@ public void initialize() throws SailException { path = path + "-shapes-graph/"; shapesRepo = new SailRepository(new MemoryStore(new File(path))); - } - else { + } else { shapesRepo = new SailRepository(new MemoryStore()); } - shapesRepo.initialize(); + shapesRepo.init(); try (SailRepositoryConnection shapesRepoConnection = shapesRepo.getConnection()) { shapesRepoConnection.begin(IsolationLevels.NONE); refreshShapes(shapesRepoConnection); shapesRepoConnection.commit(); } + initializing = false; } synchronized List refreshShapes(SailRepositoryConnection shapesRepoConnection) - throws SailException - { - try (SailRepositoryConnection beforeCommitConnection = shapesRepo.getConnection()) { - long size = beforeCommitConnection.size(); - if (size > 0) { - // Our inferencer both adds and removes statements. - // To support updates I recommend having two graphs, one raw one with the unmodified data. - // Then copy all that data into a new graph, run inferencing on that graph and use it to generate the java objects - throw new IllegalStateException( + throws SailException { + if (!initializing) { + try (SailRepositoryConnection beforeCommitConnection = shapesRepo.getConnection()) { + boolean empty = !beforeCommitConnection.hasStatement(null, null, null, false); + if (!empty) { + // Our inferencer both adds and removes statements. + // To support updates I recommend having two graphs, one raw one with the unmodified data. + // Then copy all that data into a new graph, run inferencing on that graph and use it to generate the java objects + throw new IllegalStateException( "ShaclSail does not support modifying shapes that are already loaded or loading more shapes"); + } } } @@ -293,8 +290,12 @@ public void shutDown() throws SailException { @Override public NotifyingSailConnection getConnection() throws SailException { - return new ShaclSailConnection(this, super.getConnection(), super.getConnection(), - shapesRepo.getConnection()); + return new ShaclSailConnection( + this, + super.getConnection(), + super.getConnection(), + shapesRepo.getConnection() + ); } /** @@ -313,7 +314,7 @@ public void enableValidation() { /** * Check if SHACL validation on commit() is enabled. - * + * * @return true if validation is enabled, false otherwise. */ public boolean isValidationEnabled() { @@ -322,7 +323,7 @@ public boolean isValidationEnabled() { /** * Check if logging of validation plans is enabled. - * + * * @return true if validation plan logging is enabled, false otherwise. */ public boolean isLogValidationPlans() { @@ -335,7 +336,7 @@ public boolean isIgnoreNoShapesLoadedException() { /** * Check if shapes have been loaded into the shapes graph before other data is added - * + * * @param ignoreNoShapesLoadedException */ public void setIgnoreNoShapesLoadedException(boolean ignoreNoShapesLoadedException) { @@ -345,7 +346,7 @@ public void setIgnoreNoShapesLoadedException(boolean ignoreNoShapesLoadedExcepti /** * Log (INFO) the executed validation plans as GraphViz DOT Recommended to disable parallel validation * with setParallelValidation(false) - * + * * @param logValidationPlans */ public void setLogValidationPlans(boolean logValidationPlans) { @@ -375,7 +376,7 @@ private void runInferencingSparqlQueries(SailRepositoryConnection shaclSailConne /** * Log (INFO) every execution step of the SHACL validation. This is fairly costly and should not be used * in production. Recommended to disable parallel validation with setParallelValidation(false) - * + * * @param loggingEnabled */ public void setGlobalLogValidationExecution(boolean loggingEnabled) { @@ -384,7 +385,7 @@ public void setGlobalLogValidationExecution(boolean loggingEnabled) { /** * Check if logging of every execution steps is enabled. - * + * * @return true if enabled, false otherwise. * @see #setGlobalLogValidationExecution(boolean) */ @@ -395,7 +396,7 @@ public boolean isGlobalLogValidationExecution() { /** * Check if logging a list of violations and the triples that caused the violations is enabled. It is * recommended to disable parallel validation with {@link #setParallelValidation(boolean)} - * + * * @see #setLogValidationViolations(boolean) */ public boolean isLogValidationViolations() { @@ -405,7 +406,7 @@ public boolean isLogValidationViolations() { /** * Log (INFO) a list of violations and the triples that caused the violations (BETA). Recommended to * disable parallel validation with setParallelValidation(false) - * + * * @param logValidationViolations */ public void setLogValidationViolations(boolean logValidationViolations) { @@ -416,7 +417,7 @@ public void setLogValidationViolations(boolean logValidationViolations) { * If no target is defined for a NodeShape, that NodeShape will be ignored. Calling this method with * "true" will make such NodeShapes wildcard shapes and validate all subjects. Equivalent to setting * sh:targetClass to owl:Thing or rdfs:Resource in an environment with a reasoner. - * + * * @param undefinedTargetValidatesAllSubjects * default false */ @@ -426,7 +427,7 @@ public void setUndefinedTargetValidatesAllSubjects(boolean undefinedTargetValida /** * Check if {@link NodeShape}s without a defined target are considered wildcards. - * + * * @return true if enabled, false otherwise * @see #setUndefinedTargetValidatesAllSubjects(boolean) */ @@ -436,7 +437,7 @@ public boolean isUndefinedTargetValidatesAllSubjects() { /** * Check if SHACL validation is run in parellel. - * + * * @return true if enabled, false otherwise. */ public boolean isParallelValidation() { @@ -444,18 +445,23 @@ public boolean isParallelValidation() { } /** - * Run SHACL validation in parallel. Default: true - * + * EXPERIMENTAL! Run SHACL validation in parallel. Default: false + *

+ * May cause deadlock, especially when using NativeStore. + * * @param parallelValidation - * default true - */ + * default false + */ public void setParallelValidation(boolean parallelValidation) { + if(parallelValidation){ + logger.warn("Parallel SHACL validation enabled. This is an experimental feature and may cause deadlocks!"); + } this.parallelValidation = parallelValidation; } /** * Check if selected nodes caches is enabled. - * + * * @return true if enabled, false otherwise. * @see #setCacheSelectNodes(boolean) */ @@ -467,10 +473,10 @@ public boolean isCacheSelectNodes() { * The ShaclSail retries a lot of its relevant data through running SPARQL Select queries against the * underlying sail and against the changes in the transaction. This is usually good for performance, but * while validating large amounts of data disabling this cache will use less memory. Default: true - * + * * @param cacheSelectNodes * default true - */ + */ public void setCacheSelectNodes(boolean cacheSelectNodes) { this.cacheSelectNodes = cacheSelectNodes; } diff --git a/shacl/src/main/java/org/eclipse/rdf4j/sail/shacl/ShaclSailConnection.java b/shacl/src/main/java/org/eclipse/rdf4j/sail/shacl/ShaclSailConnection.java index 48187d009..7f3169ade 100644 --- a/shacl/src/main/java/org/eclipse/rdf4j/sail/shacl/ShaclSailConnection.java +++ b/shacl/src/main/java/org/eclipse/rdf4j/sail/shacl/ShaclSailConnection.java @@ -373,33 +373,35 @@ synchronized public void close() throws SailException { @Override public void prepare() throws SailException { - preparedHasRun = true; - super.prepare(); - previousStateConnection.prepare(); + try { + preparedHasRun = true; - List nodeShapes = refreshShapes(shapesConnection); + List nodeShapes = refreshShapes(shapesConnection); - // we don't support revalidation of all data when changing the shacl shapes, - // so no need to check if the shapes have changed - if (addedStatementsSet.isEmpty() && removedStatementsSet.isEmpty()) { - logger.debug("Nothing has changed, nothing to validate."); - return; - } + // we don't support revalidation of all data when changing the shacl shapes, + // so no need to check if the shapes have changed + if (addedStatementsSet.isEmpty() && removedStatementsSet.isEmpty()) { + logger.debug("Nothing has changed, nothing to validate."); + return; + } - if (!sail.isIgnoreNoShapesLoadedException() - && ((!addedStatementsSet.isEmpty() || !removedStatementsSet.isEmpty()) - && nodeShapes.isEmpty())) { - throw new NoShapesLoadedException(); - } + if (!sail.isIgnoreNoShapesLoadedException() + && ((!addedStatementsSet.isEmpty() || !removedStatementsSet.isEmpty()) + && nodeShapes.isEmpty())) { + throw new NoShapesLoadedException(); + } - List invalidTuples = validate(); - boolean valid = invalidTuples.isEmpty(); + List invalidTuples = validate(); + boolean valid = invalidTuples.isEmpty(); - if (!valid) { - throw new ShaclSailValidationException(invalidTuples); + if (!valid) { + throw new ShaclSailValidationException(invalidTuples); + } + }finally { + super.prepare(); + previousStateConnection.prepare(); } - } @Override diff --git a/shacl/src/main/java/org/eclipse/rdf4j/sail/shacl/config/ShaclSailConfig.java b/shacl/src/main/java/org/eclipse/rdf4j/sail/shacl/config/ShaclSailConfig.java index ff571c324..07c366d35 100644 --- a/shacl/src/main/java/org/eclipse/rdf4j/sail/shacl/config/ShaclSailConfig.java +++ b/shacl/src/main/java/org/eclipse/rdf4j/sail/shacl/config/ShaclSailConfig.java @@ -34,7 +34,7 @@ */ public class ShaclSailConfig extends AbstractDelegatingSailImplConfig { - public static final boolean PARALLEL_VALIDATION_DEFAULT = true; + public static final boolean PARALLEL_VALIDATION_DEFAULT = false; public static final boolean UNDEFINED_TARGET_VALIDATES_ALL_SUBJECTS_DEFAULT = false; diff --git a/shacl/src/main/java/org/eclipse/rdf4j/sail/shacl/planNodes/BufferedPlanNode.java b/shacl/src/main/java/org/eclipse/rdf4j/sail/shacl/planNodes/BufferedPlanNode.java new file mode 100644 index 000000000..67a7b8232 --- /dev/null +++ b/shacl/src/main/java/org/eclipse/rdf4j/sail/shacl/planNodes/BufferedPlanNode.java @@ -0,0 +1,112 @@ +/******************************************************************************* + * Copyright (c) 2018 Eclipse RDF4J contributors. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Distribution License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/org/documents/edl-v10.php. + *******************************************************************************/ +package org.eclipse.rdf4j.sail.shacl.planNodes; + +import org.apache.commons.lang.StringEscapeUtils; +import org.eclipse.rdf4j.common.iteration.CloseableIteration; +import org.eclipse.rdf4j.sail.SailException; + +import java.util.ArrayDeque; +import java.util.Queue; + +public class BufferedPlanNode implements PushablePlanNode { + + private T parent; + + private Queue buffer = new ArrayDeque<>(); + private boolean closed; + private boolean printed; + + + BufferedPlanNode(T parent) { + this.parent = parent; + } + + @Override + public CloseableIteration iterator() { + return new CloseableIteration() { + + { + parent.init(); + } + + @Override + public void close() throws SailException { + closed = true; + parent.close(); + } + + @Override + public boolean hasNext() throws SailException { + calculateNext(); + return !buffer.isEmpty(); + } + + private void calculateNext() { + while (buffer.isEmpty()) { + boolean success = parent.incrementIterator(); + if (!success) { + break; + } + } + } + + @Override + public Tuple next() throws SailException { + calculateNext(); + return buffer.remove(); + } + + @Override + public void remove() throws SailException { + + } + }; + } + + @Override + public int depth() { + return parent.depth(); + } + + @Override + public void getPlanAsGraphvizDot(StringBuilder stringBuilder) { + if (printed) { + return; + } + printed = true; + parent.getPlanAsGraphvizDot(stringBuilder); + + stringBuilder.append(getId() + " [label=\"" + StringEscapeUtils.escapeJava(this.toString()) + "\"];").append("\n"); + } + + @Override + public String getId() { + return System.identityHashCode(this) + ""; + } + + @Override + public IteratorData getIteratorDataType() { + return parent.getIteratorDataType(); + } + + @Override + public void push(Tuple next) { + buffer.add(next); + } + + @Override + public boolean isClosed() { + return closed; + } + + @Override + public String toString() { + return "BufferedPlanNode"; + } +} diff --git a/shacl/src/main/java/org/eclipse/rdf4j/sail/shacl/planNodes/BufferedTupleFromFilter.java b/shacl/src/main/java/org/eclipse/rdf4j/sail/shacl/planNodes/BufferedTupleFromFilter.java deleted file mode 100644 index a596d2f98..000000000 --- a/shacl/src/main/java/org/eclipse/rdf4j/sail/shacl/planNodes/BufferedTupleFromFilter.java +++ /dev/null @@ -1,133 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2018 Eclipse RDF4J contributors. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Distribution License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/org/documents/edl-v10.php. - *******************************************************************************/ - -package org.eclipse.rdf4j.sail.shacl.planNodes; - - -import org.apache.commons.lang.StringEscapeUtils; -import org.eclipse.rdf4j.common.iteration.CloseableIteration; -import org.eclipse.rdf4j.sail.SailException; - -import java.util.LinkedList; -import java.util.List; -import java.util.stream.Collectors; - - -/** - * @author Håvard Ottestad - */ -public class BufferedTupleFromFilter implements PlanNode, PushBasedPlanNode, SupportsParentProvider { - - - private CloseableIteration parentIterator; - - LinkedList next = new LinkedList<>(); - private ParentProvider parentProvider; - private boolean printed = false; - - @Override - public CloseableIteration iterator() { - return new CloseableIteration() { - - private void calculateNext() { - if (parentIterator != null) { - while (next.isEmpty() && parentIterator.hasNext()) { - parentIterator.next(); - } - } - } - - @Override - public void close() throws SailException { - if (parentIterator != null) { - parentIterator.close(); - } - } - - @Override - public boolean hasNext() throws SailException { - calculateNext(); - return !next.isEmpty(); - } - - @Override - public Tuple next() throws SailException { - calculateNext(); - - return next.removeLast(); - } - - - @Override - public void remove() throws SailException { - - } - }; - } - - @Override - public int depth() { - return parentProvider.parent().stream().mapToInt(PlanNode::depth).max().orElse(0)+1; - } - - - @Override - public String getId() { - return System.identityHashCode(this)+""; - } - - @Override - public IteratorData getIteratorDataType() { - List collect = parentProvider.parent().stream().map(PlanNode::getIteratorDataType).distinct().collect(Collectors.toList()); - if(collect.size() == 1) return collect.get(0); - - throw new IllegalStateException("Not implemented"); - } - - @Override - public void push(Tuple t) { - if (t != null) { - next.addFirst(t); - } - } - - @Override - public void parentIterator(CloseableIteration iterator) { - parentIterator = iterator; - } - - - @Override - public void receiveParentProvider(ParentProvider parentProvider) { - this.parentProvider = parentProvider; - } - - - @Override - public void getPlanAsGraphvizDot(StringBuilder stringBuilder) { - if(printed) return; - printed = true; - - stringBuilder.append(getId() + " [label=\"" + StringEscapeUtils.escapeJava(this.toString()) + "\"];").append("\n"); - - if(parentProvider instanceof PlanNode){ - ((PlanNode) parentProvider).getPlanAsGraphvizDot(stringBuilder); - - } - - if(parentProvider instanceof FilterPlanNode){ - ((FilterPlanNode) parentProvider).getPlanAsGraphvizDot(stringBuilder); - - } - } - - @Override - public String toString() { - return "BufferedTupleFromFilter"; - } -} diff --git a/shacl/src/main/java/org/eclipse/rdf4j/sail/shacl/planNodes/DatatypeFilter.java b/shacl/src/main/java/org/eclipse/rdf4j/sail/shacl/planNodes/DatatypeFilter.java index 5f2a9e7bf..66fb97617 100644 --- a/shacl/src/main/java/org/eclipse/rdf4j/sail/shacl/planNodes/DatatypeFilter.java +++ b/shacl/src/main/java/org/eclipse/rdf4j/sail/shacl/planNodes/DatatypeFilter.java @@ -19,8 +19,8 @@ public class DatatypeFilter extends FilterPlanNode { private final Resource datatype; - public DatatypeFilter(PlanNode parent, PushBasedPlanNode trueNode, PushBasedPlanNode falseNode, Resource datatype) { - super(parent, trueNode, falseNode); + public DatatypeFilter(PlanNode parent, Resource datatype) { + super(parent); this.datatype = datatype; } diff --git a/shacl/src/main/java/org/eclipse/rdf4j/sail/shacl/planNodes/EnrichWithShape.java b/shacl/src/main/java/org/eclipse/rdf4j/sail/shacl/planNodes/EnrichWithShape.java index 01a1f9357..07c5e40fd 100644 --- a/shacl/src/main/java/org/eclipse/rdf4j/sail/shacl/planNodes/EnrichWithShape.java +++ b/shacl/src/main/java/org/eclipse/rdf4j/sail/shacl/planNodes/EnrichWithShape.java @@ -21,6 +21,7 @@ public class EnrichWithShape implements PlanNode { private final PropertyShape propertyShape; private final PlanNode parent; private boolean printed = false; + boolean closed; public EnrichWithShape(PlanNode parent, PropertyShape propertyShape) { this.parent = parent; @@ -29,6 +30,9 @@ public EnrichWithShape(PlanNode parent, PropertyShape propertyShape) { @Override public CloseableIteration iterator() { + if(closed){ + throw new IllegalStateException(); + } return new CloseableIteration() { CloseableIteration parentIterator = parent.iterator(); @@ -52,7 +56,11 @@ public void remove() throws SailException { @Override public void close() throws SailException { - parentIterator.close(); + closed = true; + if(parentIterator != null){ + parentIterator.close(); + parentIterator = null; + } } }; } diff --git a/shacl/src/main/java/org/eclipse/rdf4j/sail/shacl/planNodes/EqualsJoin.java b/shacl/src/main/java/org/eclipse/rdf4j/sail/shacl/planNodes/EqualsJoin.java index 334b808e9..49bae8de4 100644 --- a/shacl/src/main/java/org/eclipse/rdf4j/sail/shacl/planNodes/EqualsJoin.java +++ b/shacl/src/main/java/org/eclipse/rdf4j/sail/shacl/planNodes/EqualsJoin.java @@ -1,3 +1,10 @@ +/******************************************************************************* + * Copyright (c) 2018 Eclipse RDF4J contributors. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Distribution License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/org/documents/edl-v10.php. + *******************************************************************************/ package org.eclipse.rdf4j.sail.shacl.planNodes; import org.apache.commons.lang.StringEscapeUtils; @@ -176,4 +183,11 @@ public IteratorData getIteratorDataType() { throw new IllegalStateException("Not implemented support for when left and right have different types of data"); } + + @Override + public String toString() { + return "EqualsJoin{" + + "useAsFilter=" + useAsFilter + + '}'; + } } diff --git a/shacl/src/main/java/org/eclipse/rdf4j/sail/shacl/planNodes/ExistsFilter.java b/shacl/src/main/java/org/eclipse/rdf4j/sail/shacl/planNodes/ExistsFilter.java deleted file mode 100644 index b1249dce8..000000000 --- a/shacl/src/main/java/org/eclipse/rdf4j/sail/shacl/planNodes/ExistsFilter.java +++ /dev/null @@ -1,26 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2018 Eclipse RDF4J contributors. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Distribution License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/org/documents/edl-v10.php. - *******************************************************************************/ - -package org.eclipse.rdf4j.sail.shacl.planNodes; - - -/** - * @author Håvard Ottestad - */ -public class ExistsFilter extends FilterPlanNode { - - public ExistsFilter(PlanNode parent, PushBasedPlanNode trueNode, PushBasedPlanNode falseNode) { - super(parent, trueNode, falseNode); - } - - @Override - boolean checkTuple(Tuple t) { - return false; - } - -} diff --git a/shacl/src/main/java/org/eclipse/rdf4j/sail/shacl/planNodes/FilterPlanNode.java b/shacl/src/main/java/org/eclipse/rdf4j/sail/shacl/planNodes/FilterPlanNode.java index 429a9d73a..caa3cf750 100644 --- a/shacl/src/main/java/org/eclipse/rdf4j/sail/shacl/planNodes/FilterPlanNode.java +++ b/shacl/src/main/java/org/eclipse/rdf4j/sail/shacl/planNodes/FilterPlanNode.java @@ -16,51 +16,60 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import java.util.Arrays; -import java.util.List; - /** * @author Håvard Ottestad */ -public abstract class FilterPlanNode implements ParentProvider { +public abstract class FilterPlanNode implements MultiStreamPlanNode, PlanNode { static private final Logger logger = LoggerFactory.getLogger(FilterPlanNode.class); PlanNode parent; - T trueNode; - T falseNode; + PushablePlanNode trueNode; + PushablePlanNode falseNode; + + private CloseableIteration iterator; abstract boolean checkTuple(Tuple t); - public FilterPlanNode(PlanNode parent, T trueNode, T falseNode) { + public FilterPlanNode(PlanNode parent) { this.parent = parent; - this.trueNode = trueNode; - this.falseNode = falseNode; - - initialize(trueNode, falseNode); - } - private void initialize(T trueNode, T falseNode) { - CloseableIteration iterator = iterator(); - + public PlanNode getTrueNode(Class type) { if (trueNode != null) { - trueNode.parentIterator(iterator); - trueNode.receiveParentProvider(this); + throw new IllegalStateException(); } + if (type == BufferedPlanNode.class) { + trueNode = new BufferedPlanNode<>(this); + } else { + trueNode = new UnBufferedPlanNode<>(this); + } + + return trueNode; + } + + public PlanNode getFalseNode(Class type) { if (falseNode != null) { - falseNode.parentIterator(iterator); - falseNode.receiveParentProvider(this); + throw new IllegalStateException(); + } + if (type == BufferedPlanNode.class) { + falseNode = new BufferedPlanNode<>(this); + } else { + falseNode = new UnBufferedPlanNode<>(this); + } + + return falseNode; } - private CloseableIteration iterator() { - FilterPlanNode that = this; + + public CloseableIteration iterator() { + return new CloseableIteration() { CloseableIteration parentIterator; @@ -68,8 +77,8 @@ private CloseableIteration iterator() { Tuple next; private void calculateNext() { - if(parentIterator == null){ - parentIterator = parent.iterator(); + if (parentIterator == null) { + parentIterator = parent.iterator(); } if (next != null) { @@ -81,16 +90,16 @@ private void calculateNext() { if (checkTuple(temp)) { if (trueNode != null) { - if(LoggingNode.loggingEnabled){ - logger.info(leadingSpace() + that.getClass().getSimpleName() + ";trueNode: " + " " + temp.toString()); + if (LoggingNode.loggingEnabled) { + logger.info(leadingSpace() + this.getClass().getSimpleName() + ";trueNode: " + " " + temp.toString()); } trueNode.push(temp); } } else { if (falseNode != null) { - if(LoggingNode.loggingEnabled){ - logger.info(leadingSpace() + that.getClass().getSimpleName() + ";falseNode: " + " " + temp.toString()); + if (LoggingNode.loggingEnabled) { + logger.info(leadingSpace() + this.getClass().getSimpleName() + ";falseNode: " + " " + temp.toString()); } falseNode.push(temp); @@ -120,9 +129,6 @@ public void close() throws SailException { @Override public boolean hasNext() throws SailException { calculateNext(); - if (next == null) { - close(); - } return next != null; } @@ -140,42 +146,28 @@ public void remove() throws SailException { }; } - @Override - public List parent() { - return Arrays.asList(parent); - } - boolean printed = false; public void getPlanAsGraphvizDot(StringBuilder stringBuilder) { - if(printed) return; + if (printed) { + return; + } printed = true; stringBuilder.append(getId() + " [label=\"" + StringEscapeUtils.escapeJava(this.toString()) + "\"];").append("\n"); - stringBuilder.append(parent.getId()+" -> "+getId()).append("\n"); + stringBuilder.append(parent.getId() + " -> " + getId()).append("\n"); if(trueNode != null){ - String id = getId(trueNode); - stringBuilder.append(getId()+" -> "+id+ " [label=\"true values\"]").append("\n"); + stringBuilder.append(getId()+" -> "+trueNode.getId()+ " [label=\"true values\"]").append("\n"); } if(falseNode != null){ - String id = getId(falseNode); - stringBuilder.append(getId()+" -> "+id+ " [label=\"false values\"]").append("\n"); + stringBuilder.append(getId()+" -> "+falseNode.getId()+ " [label=\"false values\"]").append("\n"); } parent.getPlanAsGraphvizDot(stringBuilder); - - } - - private String getId(T node) { - if(node instanceof PlanNode){ - return ((PlanNode) node).getId(); - } - - return System.identityHashCode(node)+""; } @Override @@ -184,11 +176,50 @@ public String toString() { } public String getId() { - return System.identityHashCode(this)+""; + return System.identityHashCode(this) + ""; } private String leadingSpace() { - return StringUtils.leftPad("", parent.depth()+1, " "); + return StringUtils.leftPad("", parent.depth() + 1, " "); + } + + @Override + public void init() { + if (iterator == null) { + iterator = iterator(); + } + } + + + @Override + public void close() { + if ( + (trueNode == null || trueNode.isClosed()) && + (falseNode == null || falseNode.isClosed()) + ) { + iterator.close(); + iterator = null; + } + + } + + @Override + public boolean incrementIterator() { + if (iterator.hasNext()) { + iterator.next(); + return true; + } + return false; + } + + @Override + public int depth() { + return parent.depth() + 1; + } + + @Override + public IteratorData getIteratorDataType() { + return parent.getIteratorDataType(); } } diff --git a/shacl/src/main/java/org/eclipse/rdf4j/sail/shacl/planNodes/InnerJoin.java b/shacl/src/main/java/org/eclipse/rdf4j/sail/shacl/planNodes/InnerJoin.java index 58f904366..7c8796196 100644 --- a/shacl/src/main/java/org/eclipse/rdf4j/sail/shacl/planNodes/InnerJoin.java +++ b/shacl/src/main/java/org/eclipse/rdf4j/sail/shacl/planNodes/InnerJoin.java @@ -21,12 +21,11 @@ /** * @author Håvard Ottestad - * + *

* This inner join algorithm assumes the left iterator is unique for tuple[0], eg. no two tuples have the same value at index 0. * The right iterator is allowed to contain duplicates. - * */ -public class InnerJoin implements PlanNode, ParentProvider { +public class InnerJoin implements MultiStreamPlanNode, PlanNode { static private final Logger logger = LoggerFactory.getLogger(InnerJoin.class); private boolean printed = false; @@ -34,30 +33,67 @@ public class InnerJoin implements PlanNode, ParentProvider { private PlanNode left; private PlanNode right; + private CloseableIteration iterator; + private PushablePlanNode joined; + private PushablePlanNode discardedLeft; + private PushablePlanNode discardedRight; - private PushBasedPlanNode discardedLeft; - private PushBasedPlanNode discardedRight; - - public InnerJoin(PlanNode left, PlanNode right, PushBasedPlanNode discardedLeft, PushBasedPlanNode discardedRight) { + public InnerJoin(PlanNode left, PlanNode right) { this.left = left; this.right = right; - this.discardedLeft = discardedLeft; - this.discardedRight = discardedRight; - if(discardedLeft instanceof SupportsParentProvider){ - ((SupportsParentProvider) discardedLeft).receiveParentProvider(this); - } - if(discardedRight instanceof SupportsParentProvider){ - ((SupportsParentProvider) discardedRight).receiveParentProvider(this); - } } - @Override + public List parent() { return Arrays.asList(left, right); } - @Override + + public PlanNode getJoined(Class type) { + if (joined != null) { + throw new IllegalStateException(); + } + if (type == BufferedPlanNode.class) { + joined = new BufferedPlanNode<>(this); + } else { + joined = new UnBufferedPlanNode<>(this); + + } + + return joined; + } + + public PlanNode getDiscardedLeft(Class type) { + if (discardedLeft != null) { + throw new IllegalStateException(); + } + if (type == BufferedPlanNode.class) { + discardedLeft = new BufferedPlanNode<>(this); + } else { + discardedLeft = new UnBufferedPlanNode<>(this); + + } + return discardedLeft; + } + + public PlanNode getDiscardedRight(Class type) { + if (discardedRight != null) { + throw new IllegalStateException(); + } + if (type == BufferedPlanNode.class) { + discardedRight = new BufferedPlanNode<>(this); + } else { + discardedRight = new UnBufferedPlanNode<>(this); + + } + return discardedRight; + } + public CloseableIteration iterator() { + throw new IllegalStateException(); + } + + public CloseableIteration internalIterator() { InnerJoin that = this; return new CloseableIteration() { @@ -86,14 +122,14 @@ void calculateNext() { if (nextLeft == null) { if (discardedRight != null) { - while(nextRight != null){ - if(LoggingNode.loggingEnabled){ + while (nextRight != null) { + if (LoggingNode.loggingEnabled) { logger.info(leadingSpace() + that.getClass().getSimpleName() + ";discardedRight: " + " " + nextRight.toString()); } discardedRight.push(nextRight); - if(rightIterator.hasNext()){ + if (rightIterator.hasNext()) { nextRight = rightIterator.next(); - }else{ + } else { nextRight = null; } } @@ -115,7 +151,7 @@ void calculateNext() { if (compareTo < 0) { if (discardedLeft != null) { - if(LoggingNode.loggingEnabled){ + if (LoggingNode.loggingEnabled) { logger.info(leadingSpace() + that.getClass().getSimpleName() + ";discardedLeft: " + " " + nextLeft.toString()); } discardedLeft.push(nextLeft); @@ -128,7 +164,7 @@ void calculateNext() { } } else { if (discardedRight != null) { - if(LoggingNode.loggingEnabled){ + if (LoggingNode.loggingEnabled) { logger.info(leadingSpace() + that.getClass().getSimpleName() + ";discardedRight: " + " " + nextRight.toString()); } discardedRight.push(nextRight); @@ -177,45 +213,47 @@ public void remove() throws SailException { }; } - @Override + public int depth() { return Math.max(left.depth(), right.depth()); } - @Override + public void getPlanAsGraphvizDot(StringBuilder stringBuilder) { - if(printed) return; + if (printed) { + return; + } printed = true; left.getPlanAsGraphvizDot(stringBuilder); stringBuilder.append(getId() + " [label=\"" + StringEscapeUtils.escapeJava(this.toString()) + "\"];").append("\n"); - stringBuilder.append(left.getId()+" -> "+getId()+ " [label=\"left\"];").append("\n"); - stringBuilder.append(right.getId()+" -> "+getId()+ " [label=\"right\"];").append("\n"); + stringBuilder.append(left.getId() + " -> " + getId() + " [label=\"left\"];").append("\n"); + stringBuilder.append(right.getId() + " -> " + getId() + " [label=\"right\"];").append("\n"); right.getPlanAsGraphvizDot(stringBuilder); - if(discardedRight != null){ - if(discardedRight instanceof PlanNode){ - stringBuilder.append(getId()+" -> "+((PlanNode) discardedRight).getId()+ " [label=\"discardedRight\"];").append("\n"); - } + if (discardedRight != null) { + stringBuilder.append(getId() + " -> " + (discardedRight).getId() + " [label=\"discardedRight\"];").append("\n"); } - if(discardedLeft != null){ - if(discardedLeft instanceof PlanNode){ - stringBuilder.append(getId()+" -> "+((PlanNode) discardedLeft).getId()+ " [label=\"discardedLeft\"];").append("\n"); - } - + if (discardedLeft != null) { + stringBuilder.append(getId() + " -> " + (discardedLeft).getId() + " [label=\"discardedLeft\"];").append("\n"); + } + if (joined != null) { + stringBuilder.append(getId() + " -> " + (joined).getId() + " [label=\"joined\"];").append("\n"); } } - @Override + public String getId() { - return System.identityHashCode(this)+""; + return System.identityHashCode(this) + ""; } - @Override + public IteratorData getIteratorDataType() { - if(left.getIteratorDataType() == right.getIteratorDataType()) return left.getIteratorDataType(); + if (left.getIteratorDataType() == right.getIteratorDataType()) { + return left.getIteratorDataType(); + } throw new IllegalStateException("Not implemented support for when left and right have different types of data"); @@ -229,4 +267,44 @@ public String toString() { private String leadingSpace() { return StringUtils.leftPad("", depth(), " "); } + + @Override + public void init() { + if (iterator == null) { + iterator = internalIterator(); + } + } + + + @Override + public void close() { + + if ( + (discardedLeft == null || discardedLeft.isClosed()) && + (discardedRight == null || discardedRight.isClosed()) && + (joined == null || joined.isClosed()) + ) { + iterator.close(); + iterator = null; + } + + } + + @Override + public boolean incrementIterator() { + + if (iterator.hasNext()) { + Tuple next = iterator.next(); + if (joined != null) { + joined.push(next); + } + return true; + } + + return false; + } + } + + + diff --git a/shacl/src/main/java/org/eclipse/rdf4j/sail/shacl/planNodes/IteratorData.java b/shacl/src/main/java/org/eclipse/rdf4j/sail/shacl/planNodes/IteratorData.java index 98aefd2ae..162e1b77d 100644 --- a/shacl/src/main/java/org/eclipse/rdf4j/sail/shacl/planNodes/IteratorData.java +++ b/shacl/src/main/java/org/eclipse/rdf4j/sail/shacl/planNodes/IteratorData.java @@ -1,3 +1,10 @@ +/******************************************************************************* + * Copyright (c) 2018 Eclipse RDF4J contributors. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Distribution License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/org/documents/edl-v10.php. + *******************************************************************************/ package org.eclipse.rdf4j.sail.shacl.planNodes; public enum IteratorData { diff --git a/shacl/src/main/java/org/eclipse/rdf4j/sail/shacl/planNodes/LanguageInFilter.java b/shacl/src/main/java/org/eclipse/rdf4j/sail/shacl/planNodes/LanguageInFilter.java index 275320835..ed6d6468e 100644 --- a/shacl/src/main/java/org/eclipse/rdf4j/sail/shacl/planNodes/LanguageInFilter.java +++ b/shacl/src/main/java/org/eclipse/rdf4j/sail/shacl/planNodes/LanguageInFilter.java @@ -23,8 +23,8 @@ public class LanguageInFilter extends FilterPlanNode { private final List languageIn; - public LanguageInFilter(PlanNode parent, PushBasedPlanNode trueNode, PushBasedPlanNode falseNode, List languageIn) { - super(parent, trueNode, falseNode); + public LanguageInFilter(PlanNode parent, List languageIn) { + super(parent); this.languageIn = languageIn; } diff --git a/shacl/src/main/java/org/eclipse/rdf4j/sail/shacl/planNodes/LiteralComparatorFilter.java b/shacl/src/main/java/org/eclipse/rdf4j/sail/shacl/planNodes/LiteralComparatorFilter.java index ad5d9cd6e..9adad0b48 100644 --- a/shacl/src/main/java/org/eclipse/rdf4j/sail/shacl/planNodes/LiteralComparatorFilter.java +++ b/shacl/src/main/java/org/eclipse/rdf4j/sail/shacl/planNodes/LiteralComparatorFilter.java @@ -33,8 +33,8 @@ public class LiteralComparatorFilter extends FilterPlanNode { private final boolean timeDatatype; private final boolean dateDatatype; - public LiteralComparatorFilter(PlanNode parent, PushBasedPlanNode trueNode, PushBasedPlanNode falseNode, Literal compareTo, Function function) { - super(parent, trueNode, falseNode); + public LiteralComparatorFilter(PlanNode parent, Literal compareTo, Function function) { + super(parent); this.function = function; this.compareTo = compareTo; IRI datatype = compareTo.getDatatype(); diff --git a/shacl/src/main/java/org/eclipse/rdf4j/sail/shacl/planNodes/LoggingNode.java b/shacl/src/main/java/org/eclipse/rdf4j/sail/shacl/planNodes/LoggingNode.java index 21fb831dd..2aa618cb5 100644 --- a/shacl/src/main/java/org/eclipse/rdf4j/sail/shacl/planNodes/LoggingNode.java +++ b/shacl/src/main/java/org/eclipse/rdf4j/sail/shacl/planNodes/LoggingNode.java @@ -57,36 +57,36 @@ public CloseableIteration iterator() { } private CloseableIteration cachedIterator(CloseableIteration fromIterator) { - try (Stream stream = Iterations.stream(fromIterator)) { - List collect = stream.collect(Collectors.toList()); + Stream stream = Iterations.stream(fromIterator); + List collect = stream.collect(Collectors.toList()); - return new CloseableIteration() { + return new CloseableIteration() { - Iterator iterator = collect.iterator(); + Iterator iterator = collect.iterator(); - @Override - public void close() throws SailException { + @Override + public void close() throws SailException { - } + } - @Override - public boolean hasNext() throws SailException { - return iterator.hasNext(); - } + @Override + public boolean hasNext() throws SailException { + return iterator.hasNext(); + } - @Override - public Tuple next() throws SailException { - return iterator.next(); - } + @Override + public Tuple next() throws SailException { + return iterator.next(); + } - @Override - public void remove() throws SailException { + @Override + public void remove() throws SailException { + + } + }; - } - }; - } } diff --git a/shacl/src/main/java/org/eclipse/rdf4j/sail/shacl/planNodes/MaxCountFilter.java b/shacl/src/main/java/org/eclipse/rdf4j/sail/shacl/planNodes/MaxCountFilter.java index 24e10f7b4..565cf91ba 100644 --- a/shacl/src/main/java/org/eclipse/rdf4j/sail/shacl/planNodes/MaxCountFilter.java +++ b/shacl/src/main/java/org/eclipse/rdf4j/sail/shacl/planNodes/MaxCountFilter.java @@ -18,8 +18,8 @@ public class MaxCountFilter extends FilterPlanNode { private final long maxCount; - public MaxCountFilter(PlanNode parent, PushBasedPlanNode trueNode, PushBasedPlanNode falseNode, long maxCount) { - super(parent, trueNode, falseNode); + public MaxCountFilter(PlanNode parent, long maxCount) { + super(parent); this.maxCount = maxCount; } diff --git a/shacl/src/main/java/org/eclipse/rdf4j/sail/shacl/planNodes/MaxLengthFilter.java b/shacl/src/main/java/org/eclipse/rdf4j/sail/shacl/planNodes/MaxLengthFilter.java index ac7ddcee5..7df9b89f0 100644 --- a/shacl/src/main/java/org/eclipse/rdf4j/sail/shacl/planNodes/MaxLengthFilter.java +++ b/shacl/src/main/java/org/eclipse/rdf4j/sail/shacl/planNodes/MaxLengthFilter.java @@ -19,8 +19,8 @@ public class MaxLengthFilter extends FilterPlanNode { private final long maxLength; - public MaxLengthFilter(PlanNode parent, PushBasedPlanNode trueNode, PushBasedPlanNode falseNode, long maxLength) { - super(parent, trueNode, falseNode); + public MaxLengthFilter(PlanNode parent, long maxLength) { + super(parent); this.maxLength = maxLength; } diff --git a/shacl/src/main/java/org/eclipse/rdf4j/sail/shacl/planNodes/MinCountFilter.java b/shacl/src/main/java/org/eclipse/rdf4j/sail/shacl/planNodes/MinCountFilter.java index c8505ff56..dfe28ed2a 100644 --- a/shacl/src/main/java/org/eclipse/rdf4j/sail/shacl/planNodes/MinCountFilter.java +++ b/shacl/src/main/java/org/eclipse/rdf4j/sail/shacl/planNodes/MinCountFilter.java @@ -19,8 +19,8 @@ public class MinCountFilter extends FilterPlanNode { private final long minCount; - public MinCountFilter(PlanNode parent, PushBasedPlanNode trueNode, PushBasedPlanNode falseNode, long minCount) { - super(parent, trueNode, falseNode); + public MinCountFilter(PlanNode parent, long minCount) { + super(parent); this.minCount = minCount; } diff --git a/shacl/src/main/java/org/eclipse/rdf4j/sail/shacl/planNodes/MinExclusiveFilter.java b/shacl/src/main/java/org/eclipse/rdf4j/sail/shacl/planNodes/MinExclusiveFilter.java index 0feec4782..e76e285a9 100644 --- a/shacl/src/main/java/org/eclipse/rdf4j/sail/shacl/planNodes/MinExclusiveFilter.java +++ b/shacl/src/main/java/org/eclipse/rdf4j/sail/shacl/planNodes/MinExclusiveFilter.java @@ -21,8 +21,8 @@ public class MinExclusiveFilter extends FilterPlanNode { private final BigDecimal min; - public MinExclusiveFilter(PlanNode parent, PushBasedPlanNode trueNode, PushBasedPlanNode falseNode, BigDecimal min) { - super(parent, trueNode, falseNode); + public MinExclusiveFilter(PlanNode parent, BigDecimal min) { + super(parent); this.min = min; } diff --git a/shacl/src/main/java/org/eclipse/rdf4j/sail/shacl/planNodes/MinLengthFilter.java b/shacl/src/main/java/org/eclipse/rdf4j/sail/shacl/planNodes/MinLengthFilter.java index be7bcd6c0..645aee9b0 100644 --- a/shacl/src/main/java/org/eclipse/rdf4j/sail/shacl/planNodes/MinLengthFilter.java +++ b/shacl/src/main/java/org/eclipse/rdf4j/sail/shacl/planNodes/MinLengthFilter.java @@ -18,8 +18,8 @@ public class MinLengthFilter extends FilterPlanNode { private final long minLength; - public MinLengthFilter(PlanNode parent, PushBasedPlanNode trueNode, PushBasedPlanNode falseNode, long minLength) { - super(parent, trueNode, falseNode); + public MinLengthFilter(PlanNode parent, long minLength) { + super(parent); this.minLength = minLength; } diff --git a/shacl/src/main/java/org/eclipse/rdf4j/sail/shacl/planNodes/SupportsParentProvider.java b/shacl/src/main/java/org/eclipse/rdf4j/sail/shacl/planNodes/MultiStreamPlanNode.java similarity index 70% rename from shacl/src/main/java/org/eclipse/rdf4j/sail/shacl/planNodes/SupportsParentProvider.java rename to shacl/src/main/java/org/eclipse/rdf4j/sail/shacl/planNodes/MultiStreamPlanNode.java index 3629fc7ee..1fd13e403 100644 --- a/shacl/src/main/java/org/eclipse/rdf4j/sail/shacl/planNodes/SupportsParentProvider.java +++ b/shacl/src/main/java/org/eclipse/rdf4j/sail/shacl/planNodes/MultiStreamPlanNode.java @@ -8,19 +8,10 @@ package org.eclipse.rdf4j.sail.shacl.planNodes; -import java.util.List; +public interface MultiStreamPlanNode { + void init(); -public interface SupportsParentProvider { - - void receiveParentProvider(ParentProvider parentProvider); + void close(); + boolean incrementIterator(); } - -/** - * @author Håvard Ottestad - */ -interface ParentProvider { - - List parent(); - -} \ No newline at end of file diff --git a/shacl/src/main/java/org/eclipse/rdf4j/sail/shacl/planNodes/NodeKindFilter.java b/shacl/src/main/java/org/eclipse/rdf4j/sail/shacl/planNodes/NodeKindFilter.java index 5838b9fd6..20d2e2ed2 100644 --- a/shacl/src/main/java/org/eclipse/rdf4j/sail/shacl/planNodes/NodeKindFilter.java +++ b/shacl/src/main/java/org/eclipse/rdf4j/sail/shacl/planNodes/NodeKindFilter.java @@ -23,8 +23,8 @@ public class NodeKindFilter extends FilterPlanNode { private final NodeKindPropertyShape.NodeKind nodeKind; - public NodeKindFilter(PlanNode parent, PushBasedPlanNode trueNode, PushBasedPlanNode falseNode, NodeKindPropertyShape.NodeKind nodeKind) { - super(parent, trueNode, falseNode); + public NodeKindFilter(PlanNode parent, NodeKindPropertyShape.NodeKind nodeKind) { + super(parent); this.nodeKind = nodeKind; } diff --git a/shacl/src/main/java/org/eclipse/rdf4j/sail/shacl/planNodes/PatternFilter.java b/shacl/src/main/java/org/eclipse/rdf4j/sail/shacl/planNodes/PatternFilter.java index 257b4aded..39e97ff1e 100644 --- a/shacl/src/main/java/org/eclipse/rdf4j/sail/shacl/planNodes/PatternFilter.java +++ b/shacl/src/main/java/org/eclipse/rdf4j/sail/shacl/planNodes/PatternFilter.java @@ -23,8 +23,8 @@ public class PatternFilter extends FilterPlanNode { private final Pattern pattern; - public PatternFilter(PlanNode parent, PushBasedPlanNode trueNode, PushBasedPlanNode falseNode, String pattern, Optional flags) { - super(parent, trueNode, falseNode); + public PatternFilter(PlanNode parent, String pattern, Optional flags) { + super(parent); if (flags.isPresent()) { int flag = 0b0; diff --git a/shacl/src/main/java/org/eclipse/rdf4j/sail/shacl/planNodes/PushBasedLoggingNode.java b/shacl/src/main/java/org/eclipse/rdf4j/sail/shacl/planNodes/PushBasedLoggingNode.java deleted file mode 100644 index 9426bfa45..000000000 --- a/shacl/src/main/java/org/eclipse/rdf4j/sail/shacl/planNodes/PushBasedLoggingNode.java +++ /dev/null @@ -1,72 +0,0 @@ -package org.eclipse.rdf4j.sail.shacl.planNodes; - -import org.apache.commons.lang.StringUtils; -import org.eclipse.rdf4j.common.iteration.CloseableIteration; -import org.eclipse.rdf4j.sail.SailException; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import java.util.List; - -public class PushBasedLoggingNode implements SupportsParentProvider, PushBasedPlanNode, PlanNode { - - static private final Logger logger = LoggerFactory.getLogger(PushBasedLoggingNode.class); - - - private final PushBasedPlanNode parent; - private List parents; - - public PushBasedLoggingNode(PushBasedPlanNode parent) { - this.parent = parent; - } - - - @Override - public CloseableIteration iterator() { - throw new IllegalStateException(); - } - - @Override - public int depth() { - return ((PlanNode)parent).depth(); - } - - @Override - public void getPlanAsGraphvizDot(StringBuilder stringBuilder) { - ((PlanNode)parent).getPlanAsGraphvizDot(stringBuilder); - } - - @Override - public String getId() { - return ((PlanNode)parent).getId(); - } - - @Override - public IteratorData getIteratorDataType() { - return ((PlanNode)parent).getIteratorDataType(); - } - - @Override - public void push(Tuple t) { - if(LoggingNode.loggingEnabled){ - logger.info(leadingSpace() + parent.getClass().getSimpleName() + ".next(): " + " " + t.toString()); - } - parent.push(t); - } - - @Override - public void parentIterator(CloseableIteration iterator) { - this.parent.parentIterator(iterator); - } - - @Override - public void receiveParentProvider(ParentProvider parentProvider) { - - this.parents = parentProvider.parent(); - ((SupportsParentProvider)this.parent).receiveParentProvider(parentProvider); - } - - private String leadingSpace() { - return StringUtils.leftPad("", depth(), " "); - } -} diff --git a/shacl/src/main/java/org/eclipse/rdf4j/sail/shacl/planNodes/PushBasedPlanNode.java b/shacl/src/main/java/org/eclipse/rdf4j/sail/shacl/planNodes/PushablePlanNode.java similarity index 65% rename from shacl/src/main/java/org/eclipse/rdf4j/sail/shacl/planNodes/PushBasedPlanNode.java rename to shacl/src/main/java/org/eclipse/rdf4j/sail/shacl/planNodes/PushablePlanNode.java index 9b255f6e2..3b7aca17e 100644 --- a/shacl/src/main/java/org/eclipse/rdf4j/sail/shacl/planNodes/PushBasedPlanNode.java +++ b/shacl/src/main/java/org/eclipse/rdf4j/sail/shacl/planNodes/PushablePlanNode.java @@ -8,17 +8,9 @@ package org.eclipse.rdf4j.sail.shacl.planNodes; -import org.eclipse.rdf4j.common.iteration.CloseableIteration; -import org.eclipse.rdf4j.sail.SailException; - -/** - * @author Håvard Ottestad - */ -public interface PushBasedPlanNode { - - void push(Tuple t); - - void parentIterator(CloseableIteration iterator); +public interface PushablePlanNode extends PlanNode { + void push(Tuple tuple); + boolean isClosed(); } diff --git a/shacl/src/main/java/org/eclipse/rdf4j/sail/shacl/planNodes/SetFilterNode.java b/shacl/src/main/java/org/eclipse/rdf4j/sail/shacl/planNodes/SetFilterNode.java new file mode 100644 index 000000000..b0a29ca2d --- /dev/null +++ b/shacl/src/main/java/org/eclipse/rdf4j/sail/shacl/planNodes/SetFilterNode.java @@ -0,0 +1,117 @@ +/******************************************************************************* + * Copyright (c) 2018 Eclipse RDF4J contributors. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Distribution License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/org/documents/edl-v10.php. + *******************************************************************************/ + +package org.eclipse.rdf4j.sail.shacl.planNodes; + +import org.apache.commons.lang.StringEscapeUtils; +import org.eclipse.rdf4j.common.iteration.CloseableIteration; +import org.eclipse.rdf4j.model.Value; +import org.eclipse.rdf4j.sail.SailException; + +import java.util.Arrays; +import java.util.Set; + +public class SetFilterNode implements PlanNode { + + private Set targetNodeList; + private PlanNode parent; + private int index; + private boolean returnValid; + private boolean printed; + + public SetFilterNode(Set targetNodeList, PlanNode parent, int index, boolean returnValid) { + this.targetNodeList = targetNodeList; + this.parent = parent; + this.index = index; + this.returnValid = returnValid; + } + + @Override + public CloseableIteration iterator() { + return new CloseableIteration() { + + CloseableIteration iterator = parent.iterator(); + + Tuple next; + + private void calulateNext(){ + while(next == null && iterator.hasNext()){ + Tuple temp = iterator.next(); + boolean contains = targetNodeList.contains(temp.getlist().get(index)); + if(returnValid && contains){ + next = temp; + }else if (!returnValid && !contains){ + next = temp; + } + } + } + + @Override + public void close() throws SailException { + iterator.close(); + } + + @Override + public boolean hasNext() throws SailException { + calulateNext(); + return next != null; + } + + @Override + public Tuple next() throws SailException { + calulateNext(); + + Tuple temp = next; + next = null; + + return temp; + } + + @Override + public void remove() throws SailException { + + } + }; + } + + @Override + public int depth() { + return parent.depth() + 1; + } + + @Override + public void getPlanAsGraphvizDot(StringBuilder stringBuilder) { + if (printed) { + return; + } + printed = true; + stringBuilder.append(getId() + " [label=\"" + StringEscapeUtils.escapeJava(this.toString()) + "\"];").append("\n"); + stringBuilder.append(parent.getId() + " -> " + getId()).append("\n"); + parent.getPlanAsGraphvizDot(stringBuilder); + } + + @Override + public String getId() { + return System.identityHashCode(this) + ""; + } + + + @Override + public IteratorData getIteratorDataType() { + return parent.getIteratorDataType(); + } + + @Override + public String toString() { + return "SetFilterNode{" + + "targetNodeList=" + Arrays.toString(targetNodeList.toArray()) + + ", index=" + index + + ", returnValid=" + returnValid + + '}'; + } +} diff --git a/shacl/src/main/java/org/eclipse/rdf4j/sail/shacl/planNodes/TrimTuple.java b/shacl/src/main/java/org/eclipse/rdf4j/sail/shacl/planNodes/TrimTuple.java index f61e205af..cea4f1536 100644 --- a/shacl/src/main/java/org/eclipse/rdf4j/sail/shacl/planNodes/TrimTuple.java +++ b/shacl/src/main/java/org/eclipse/rdf4j/sail/shacl/planNodes/TrimTuple.java @@ -92,8 +92,7 @@ public void getPlanAsGraphvizDot(StringBuilder stringBuilder) { @Override public String toString() { return "TrimTuple{" + - "parent=" + parent + - ", newLength=" + newLength + + "newLength=" + newLength + ", startIndex=" + startIndex + '}'; } diff --git a/shacl/src/main/java/org/eclipse/rdf4j/sail/shacl/planNodes/TupleLengthFilter.java b/shacl/src/main/java/org/eclipse/rdf4j/sail/shacl/planNodes/TupleLengthFilter.java index 45c065858..ac8b3f1fb 100644 --- a/shacl/src/main/java/org/eclipse/rdf4j/sail/shacl/planNodes/TupleLengthFilter.java +++ b/shacl/src/main/java/org/eclipse/rdf4j/sail/shacl/planNodes/TupleLengthFilter.java @@ -13,8 +13,8 @@ public class TupleLengthFilter extends FilterPlanNode{ private final boolean exact; - public TupleLengthFilter(PlanNode parent, PushBasedPlanNode trueNode, PushBasedPlanNode falseNode, int length, boolean exact) { - super(parent, trueNode, falseNode); + public TupleLengthFilter(PlanNode parent, int length, boolean exact) { + super(parent); this.length = length; this.exact = exact; } diff --git a/shacl/src/main/java/org/eclipse/rdf4j/sail/shacl/planNodes/DirectTupleFromFilter.java b/shacl/src/main/java/org/eclipse/rdf4j/sail/shacl/planNodes/UnBufferedPlanNode.java similarity index 54% rename from shacl/src/main/java/org/eclipse/rdf4j/sail/shacl/planNodes/DirectTupleFromFilter.java rename to shacl/src/main/java/org/eclipse/rdf4j/sail/shacl/planNodes/UnBufferedPlanNode.java index d082e110c..22f3200c1 100644 --- a/shacl/src/main/java/org/eclipse/rdf4j/sail/shacl/planNodes/DirectTupleFromFilter.java +++ b/shacl/src/main/java/org/eclipse/rdf4j/sail/shacl/planNodes/UnBufferedPlanNode.java @@ -8,39 +8,37 @@ package org.eclipse.rdf4j.sail.shacl.planNodes; - import org.apache.commons.lang.StringEscapeUtils; import org.eclipse.rdf4j.common.iteration.CloseableIteration; import org.eclipse.rdf4j.sail.SailException; -import java.util.List; -import java.util.stream.Collectors; - -/** - * @author Håvard Ottestad - */ -public class DirectTupleFromFilter implements PlanNode, PushBasedPlanNode, SupportsParentProvider { +public class UnBufferedPlanNode implements PushablePlanNode { - private boolean printed = false; + private T parent; - private CloseableIteration parentIterator; + Tuple next; + private boolean closed; + private boolean printed; - Tuple next = null; - private ParentProvider parentProvider; + UnBufferedPlanNode(T parent) { + this.parent = parent; + } @Override public CloseableIteration iterator() { + next = null; + closed = false; + return new CloseableIteration() { - private void calculateNext() { - while (next == null && parentIterator.hasNext()) { - parentIterator.next(); - } + { + parent.init(); } @Override public void close() throws SailException { - parentIterator.close(); + closed = true; + parent.close(); } @Override @@ -49,16 +47,21 @@ public boolean hasNext() throws SailException { return next != null; } + private void calculateNext() { + while(next == null){ + boolean success = parent.incrementIterator(); + if(!success) break; + } + } + @Override public Tuple next() throws SailException { calculateNext(); Tuple temp = next; next = null; - return temp; } - @Override public void remove() throws SailException { @@ -68,57 +71,41 @@ public void remove() throws SailException { @Override public int depth() { - return parentProvider.parent().stream().mapToInt(PlanNode::depth).sum()+2; + return parent.depth(); } @Override public void getPlanAsGraphvizDot(StringBuilder stringBuilder) { - if(printed) return; - printed = true; - stringBuilder.append(getId() + " [label=\"" + StringEscapeUtils.escapeJava(this.toString()) + "\"];").append("\n"); - - if(parentProvider instanceof PlanNode){ - ((PlanNode) parentProvider).getPlanAsGraphvizDot(stringBuilder); - + if (printed) { + return; } + printed = true; + parent.getPlanAsGraphvizDot(stringBuilder); - if(parentProvider instanceof FilterPlanNode){ - ((FilterPlanNode) parentProvider).getPlanAsGraphvizDot(stringBuilder); - - } - } - - @Override - public String toString() { - return "DirectTupleFromFilter"; + stringBuilder.append(getId() + " [label=\"" + StringEscapeUtils.escapeJava(this.toString()) + "\"];").append("\n"); } @Override public String getId() { - return System.identityHashCode(this)+""; + return System.identityHashCode(this) + ""; } - @Override public IteratorData getIteratorDataType() { - List collect = parentProvider.parent().stream().map(PlanNode::getIteratorDataType).distinct().collect(Collectors.toList()); - if(collect.size() == 1) return collect.get(0); - - throw new IllegalStateException("Not implemented yet"); + return parent.getIteratorDataType(); } @Override - public void push(Tuple t) { - next = t; + public void push(Tuple next) { + this.next = next; } @Override - public void parentIterator(CloseableIteration iterator) { - parentIterator = iterator; + public boolean isClosed() { + return closed; } - @Override - public void receiveParentProvider(ParentProvider parentProvider) { - this.parentProvider = parentProvider; + public String toString() { + return "UnBufferedPlanNode"; } } diff --git a/shacl/src/test/java/org/eclipse/rdf4j/sail/shacl/AbstractShaclTest.java b/shacl/src/test/java/org/eclipse/rdf4j/sail/shacl/AbstractShaclTest.java index 56c1c0e98..2eb53baf4 100644 --- a/shacl/src/test/java/org/eclipse/rdf4j/sail/shacl/AbstractShaclTest.java +++ b/shacl/src/test/java/org/eclipse/rdf4j/sail/shacl/AbstractShaclTest.java @@ -48,12 +48,15 @@ abstract public class AbstractShaclTest { "test-cases/languageIn/simple", "test-cases/nodeKind/simple", "test-cases/minCount/simple", + "test-cases/minCount/targetNode", "test-cases/maxCount/simple", + "test-cases/maxCount/targetNode", "test-cases/or/inheritance", "test-cases/or/inheritance-deep", "test-cases/or/inheritance-deep-minCountMaxCount", "test-cases/or/inheritanceNodeShape", "test-cases/or/datatype", + "test-cases/or/datatypeTargetNode", "test-cases/or/minCountMaxCount", "test-cases/or/maxCount", "test-cases/or/minCount", @@ -68,9 +71,12 @@ abstract public class AbstractShaclTest { "test-cases/implicitTargetClass/simple", "test-cases/class/simple", "test-cases/class/subclass", + "test-cases/class/targetNode", "test-cases/or/class", "test-cases/or/datatype2", - "test-cases/or/minCountDifferentPath" + "test-cases/or/minCountDifferentPath", + "test-cases/datatype/targetNode" + ); final String testCasePath; @@ -147,6 +153,7 @@ static void runTestCase(String shaclPath, String dataPath, ExpectedResult expect System.out.println(shaclFile); ShaclSail shaclSail = new ShaclSail(new MemoryStore()); shaclSail.setLogValidationPlans(true); +// shaclSail.setParallelValidation(false); SailRepository shaclRepository = new SailRepository(shaclSail); shaclRepository.init(); Utils.loadShapeData(shaclRepository, shaclFile); @@ -220,6 +227,7 @@ static void runTestCaseSingleTransaction(String shaclPath, String dataPath, Expe ShaclSail shaclSail = new ShaclSail(new MemoryStore()); SailRepository shaclRepository = new SailRepository(shaclSail); + shaclSail.setLogValidationPlans(true); shaclRepository.init(); Utils.loadShapeData(shaclRepository, shaclPath + "shacl.ttl"); diff --git a/shacl/src/test/java/org/eclipse/rdf4j/sail/shacl/DeadlockTest.java b/shacl/src/test/java/org/eclipse/rdf4j/sail/shacl/DeadlockTest.java new file mode 100644 index 000000000..e72097625 --- /dev/null +++ b/shacl/src/test/java/org/eclipse/rdf4j/sail/shacl/DeadlockTest.java @@ -0,0 +1,47 @@ +package org.eclipse.rdf4j.sail.shacl; + +import org.assertj.core.util.Files; +import org.eclipse.rdf4j.IsolationLevels; +import org.eclipse.rdf4j.common.io.IOUtil; +import org.eclipse.rdf4j.repository.sail.SailRepository; +import org.eclipse.rdf4j.repository.sail.SailRepositoryConnection; +import org.eclipse.rdf4j.sail.nativerdf.NativeStore; +import org.junit.Test; + +import java.io.File; +import java.io.IOException; + +public class DeadlockTest { + + @Test + public void test() throws IOException { + + for (int i = 0; i < 10; i++) { + + String shaclPath = "complexBenchmark/"; + + File dataDir = Files.newTemporaryFolder(); + dataDir.deleteOnExit(); + + ShaclSail shaclSail = new ShaclSail(new NativeStore(dataDir)); + SailRepository shaclRepository = new SailRepository(shaclSail); + shaclRepository.init(); + + shaclSail.setParallelValidation(true); + + Utils.loadShapeData(shaclRepository, shaclPath + "shacl.ttl"); + + try (SailRepositoryConnection connection = shaclRepository.getConnection()) { + + connection.begin(IsolationLevels.SNAPSHOT); + connection.prepareUpdate(IOUtil.readString(DeadlockTest.class.getClassLoader().getResourceAsStream(shaclPath + "transaction1.qr"))).execute(); + connection.commit(); + + connection.begin(IsolationLevels.SNAPSHOT); + connection.prepareUpdate(IOUtil.readString(DeadlockTest.class.getClassLoader().getResourceAsStream(shaclPath + "transaction2.qr"))).execute(); + connection.commit(); + } + } + } + +} diff --git a/shacl/src/test/java/org/eclipse/rdf4j/sail/shacl/InnerJoinTest.java b/shacl/src/test/java/org/eclipse/rdf4j/sail/shacl/InnerJoinTest.java index a846b2463..113c0d9b5 100644 --- a/shacl/src/test/java/org/eclipse/rdf4j/sail/shacl/InnerJoinTest.java +++ b/shacl/src/test/java/org/eclipse/rdf4j/sail/shacl/InnerJoinTest.java @@ -12,6 +12,7 @@ import org.eclipse.rdf4j.model.impl.SimpleValueFactory; import org.eclipse.rdf4j.sail.shacl.mock.MockConsumePlanNode; import org.eclipse.rdf4j.sail.shacl.mock.MockInputPlanNode; +import org.eclipse.rdf4j.sail.shacl.planNodes.BufferedPlanNode; import org.eclipse.rdf4j.sail.shacl.planNodes.InnerJoin; import org.eclipse.rdf4j.sail.shacl.planNodes.LoggingNode; import org.eclipse.rdf4j.sail.shacl.planNodes.PlanNode; @@ -42,7 +43,7 @@ public void testSimple() { PlanNode left = new MockInputPlanNode(Arrays.asList("a")); PlanNode right = new MockInputPlanNode(Arrays.asList("a", "b")); - InnerJoin innerJoin = new InnerJoin(left, right, null, null); + PlanNode innerJoin = new InnerJoin(left, right).getJoined(BufferedPlanNode.class); List tuples = new MockConsumePlanNode(innerJoin).asList(); @@ -60,7 +61,7 @@ public void testSimple2() { PlanNode left = new MockInputPlanNode(Arrays.asList("a1"), Arrays.asList("a2")); PlanNode right = new MockInputPlanNode(Arrays.asList("a1", "b")); - InnerJoin innerJoin = new InnerJoin(left, right, null, null); + PlanNode innerJoin = new InnerJoin(left, right).getJoined(BufferedPlanNode.class); List tuples = new MockConsumePlanNode(innerJoin).asList(); @@ -78,7 +79,7 @@ public void testSimple3() { PlanNode left = new MockInputPlanNode(Arrays.asList("a1"), Arrays.asList("a2")); PlanNode right = new MockInputPlanNode(Arrays.asList("a2", "b")); - InnerJoin innerJoin = new InnerJoin(left, right, null, null); + PlanNode innerJoin = new InnerJoin(left, right).getJoined(BufferedPlanNode.class); List tuples = new MockConsumePlanNode(innerJoin).asList(); @@ -96,7 +97,7 @@ public void testSimple4() { PlanNode left = new MockInputPlanNode(Arrays.asList("a1"), Arrays.asList("a2")); PlanNode right = new MockInputPlanNode(Arrays.asList()); - InnerJoin innerJoin = new InnerJoin(left, right, null, null); + PlanNode innerJoin = new InnerJoin(left, right).getJoined(BufferedPlanNode.class); List tuples = new MockConsumePlanNode(innerJoin).asList(); @@ -114,7 +115,7 @@ public void testSimple5() { PlanNode left = new MockInputPlanNode(); PlanNode right = new MockInputPlanNode(Arrays.asList("a1"), Arrays.asList("a2")); - InnerJoin innerJoin = new InnerJoin(left, right, null, null); + PlanNode innerJoin = new InnerJoin(left, right).getJoined(BufferedPlanNode.class); List tuples = new MockConsumePlanNode(innerJoin).asList(); @@ -131,7 +132,7 @@ public void testSimple6() { PlanNode left = new MockInputPlanNode(Arrays.asList("a1"), Arrays.asList("a2"), Arrays.asList("a3"), Arrays.asList("a4")); PlanNode right = new MockInputPlanNode(Arrays.asList("a1", "b1"), Arrays.asList("a2", "b2"), Arrays.asList("a3", "b3"), Arrays.asList("a4", "b4")); - InnerJoin innerJoin = new InnerJoin(left, right, null, null); + PlanNode innerJoin = new InnerJoin(left, right).getJoined(BufferedPlanNode.class); List tuples = new MockConsumePlanNode(innerJoin).asList(); @@ -148,7 +149,7 @@ public void testSimple7() { PlanNode left = new MockInputPlanNode(Arrays.asList("a1"), Arrays.asList("a2")); PlanNode right = new MockInputPlanNode(Arrays.asList("a1", "b1"), Arrays.asList("a2", "b2")); - InnerJoin innerJoin = new InnerJoin(left, right, null, null); + PlanNode innerJoin = new InnerJoin(left, right).getJoined(BufferedPlanNode.class); List tuples = new MockConsumePlanNode(innerJoin).asList(); @@ -165,7 +166,7 @@ public void testSimple8() { PlanNode left = new MockInputPlanNode(Arrays.asList("a1"), Arrays.asList("a2"), Arrays.asList("a3")); PlanNode right = new MockInputPlanNode(Arrays.asList("a1", "b1"), Arrays.asList("a2", "b2"), Arrays.asList("a3", "b3")); - PlanNode innerJoin = new LoggingNode(new InnerJoin(left, right, null, null), ""); + PlanNode innerJoin = new InnerJoin(left, right).getJoined(BufferedPlanNode.class); List tuples = new MockConsumePlanNode(innerJoin).asList(); @@ -182,7 +183,7 @@ public void testSimple9() { PlanNode left = new MockInputPlanNode(Arrays.asList("a1"), Arrays.asList("a2"), Arrays.asList("a3"), Arrays.asList("a4")); PlanNode right = new MockInputPlanNode(Arrays.asList("a1", "b1"), Arrays.asList("a2", "b2"), Arrays.asList("a2", "b22"), Arrays.asList("a3", "b3"), Arrays.asList("a4", "b4")); - InnerJoin innerJoin = new InnerJoin(left, right, null, null); + PlanNode innerJoin = new InnerJoin(left, right).getJoined(BufferedPlanNode.class); List tuples = new MockConsumePlanNode(innerJoin).asList(); @@ -199,7 +200,7 @@ public void testSimple10() { PlanNode left = new MockInputPlanNode(Arrays.asList("a1"), Arrays.asList("a2"), Arrays.asList("a3"), Arrays.asList("a4")); PlanNode right = new MockInputPlanNode(Arrays.asList("a1", "b1"), Arrays.asList("a2", "b2"), Arrays.asList("a2", "b22"), Arrays.asList("a4", "b4")); - InnerJoin innerJoin = new InnerJoin(left, right, null, null); + PlanNode innerJoin = new InnerJoin(left, right).getJoined(BufferedPlanNode.class); List tuples = new MockConsumePlanNode(innerJoin).asList(); @@ -217,7 +218,7 @@ public void testSimple11() { PlanNode left = new MockInputPlanNode(Arrays.asList("a1"), Arrays.asList("a2"), Arrays.asList("a3"), Arrays.asList("a4")); PlanNode right = new MockInputPlanNode(Arrays.asList("a2", "b2"), Arrays.asList("a2", "b22"), Arrays.asList("a4", "b4")); - InnerJoin innerJoin = new InnerJoin(left, right, null, null); + PlanNode innerJoin = new InnerJoin(left, right).getJoined(BufferedPlanNode.class); List tuples = new MockConsumePlanNode(innerJoin).asList(); @@ -234,7 +235,7 @@ public void testSimple12() { PlanNode left = new MockInputPlanNode(Arrays.asList("a1"), Arrays.asList("a2"), Arrays.asList("a3"), Arrays.asList("a4")); PlanNode right = new MockInputPlanNode(Arrays.asList("a2", "b2"), Arrays.asList("a2", "b22")); - InnerJoin innerJoin = new InnerJoin(left, right, null, null); + PlanNode innerJoin = new InnerJoin(left, right).getJoined(BufferedPlanNode.class); List tuples = new MockConsumePlanNode(innerJoin).asList(); @@ -252,7 +253,7 @@ public void testSimple13() { PlanNode left = new MockInputPlanNode(Arrays.asList("a1"), Arrays.asList("a2"), Arrays.asList("a3"), Arrays.asList("a4")); PlanNode right = new MockInputPlanNode(Arrays.asList("a1", "b1"), Arrays.asList("a1", "b11"), Arrays.asList("a2", "b2"), Arrays.asList("a2", "b22")); - InnerJoin innerJoin = new InnerJoin(left, right, null, null); + PlanNode innerJoin = new InnerJoin(left, right).getJoined(BufferedPlanNode.class); List tuples = new MockConsumePlanNode(innerJoin).asList(); diff --git a/shacl/src/test/java/org/eclipse/rdf4j/sail/shacl/NativeStoreTest.java b/shacl/src/test/java/org/eclipse/rdf4j/sail/shacl/NativeStoreTest.java new file mode 100644 index 000000000..04b7d2fd6 --- /dev/null +++ b/shacl/src/test/java/org/eclipse/rdf4j/sail/shacl/NativeStoreTest.java @@ -0,0 +1,124 @@ +/******************************************************************************* + * Copyright (c) 2019 Eclipse RDF4J contributors. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Distribution License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/org/documents/edl-v10.php. + *******************************************************************************/ +package org.eclipse.rdf4j.sail.shacl; + +import org.assertj.core.util.Files; +import org.eclipse.rdf4j.model.vocabulary.RDF4J; +import org.eclipse.rdf4j.repository.RepositoryException; +import org.eclipse.rdf4j.repository.sail.SailRepository; +import org.eclipse.rdf4j.repository.sail.SailRepositoryConnection; +import org.eclipse.rdf4j.rio.RDFFormat; +import org.eclipse.rdf4j.sail.nativerdf.NativeStore; +import org.junit.Test; + +import java.io.File; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.io.StringReader; + +public class NativeStoreTest { + + @Test + public void testEmpty() throws IOException { + + File file = Files.newTemporaryFolder(); + + SailRepository shaclSail = new SailRepository(new ShaclSail(new NativeStore(file))); + shaclSail.init(); + + shaclSail.shutDown(); + + delete(file); + } + + @Test(expected = ShaclSailValidationException.class) + public void testPersistedShapes() throws Throwable { + + File file = Files.newTemporaryFolder(); + + SailRepository shaclSail = new SailRepository(new ShaclSail(new NativeStore(file))); + shaclSail.init(); + addShapes(shaclSail); + shaclSail.shutDown(); + + shaclSail = new SailRepository(new ShaclSail(new NativeStore(file))); + shaclSail.init(); + + try (SailRepositoryConnection connection = shaclSail.getConnection()) { + + connection.begin(); + + StringReader invalidSampleData = new StringReader( + String.join("\n", "", + "@prefix ex: .", + "@prefix foaf: .", + "@prefix xsd: .", + + "ex:peter a foaf:Person ;", + " foaf:age 20, \"30\"^^xsd:int ." + + )); + + connection.add(invalidSampleData, "", RDFFormat.TURTLE); + try { + connection.commit(); + } catch (RepositoryException exception) { + throw exception.getCause(); + + } + } + + shaclSail.shutDown(); + + delete(file); + } + + private void addShapes(SailRepository shaclSail) throws IOException { + try (SailRepositoryConnection connection = shaclSail.getConnection()) { + + connection.begin(); + + StringReader shaclRules = new StringReader( + String.join("\n", "", + "@prefix ex: .", + "@prefix sh: .", + "@prefix xsd: .", + "@prefix foaf: .", + + "ex:PersonShape", + " a sh:NodeShape ;", + " sh:targetClass foaf:Person ;", + " sh:property ex:PersonShapeProperty .", + + "ex:PersonShapeProperty ", + " sh:path foaf:age ;", + " sh:datatype xsd:int ;", + " sh:maxCount 1 ;", + " sh:minCount 1 ." + )); + + connection.add(shaclRules, "", RDFFormat.TURTLE, RDF4J.SHACL_SHAPE_GRAPH); + connection.commit(); + + } + } + + void delete(File f) throws IOException { + if (f.isDirectory()) { + for (File c : f.listFiles()) { + delete(c); + } + } + if (!f.delete()) { + throw new FileNotFoundException("Failed to delete file: " + f); + } + } + +} + + diff --git a/shacl/src/test/java/org/eclipse/rdf4j/sail/shacl/benchmark/ClassBenchmarkEmpty.java b/shacl/src/test/java/org/eclipse/rdf4j/sail/shacl/benchmark/ClassBenchmarkEmpty.java new file mode 100644 index 000000000..71383b9a6 --- /dev/null +++ b/shacl/src/test/java/org/eclipse/rdf4j/sail/shacl/benchmark/ClassBenchmarkEmpty.java @@ -0,0 +1,159 @@ +/******************************************************************************* + * Copyright (c) 2018 Eclipse RDF4J contributors. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Distribution License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/org/documents/edl-v10.php. + *******************************************************************************/ + +package org.eclipse.rdf4j.sail.shacl.benchmark; + +import ch.qos.logback.classic.Logger; +import org.eclipse.rdf4j.common.iteration.Iterations; +import org.eclipse.rdf4j.model.Statement; +import org.eclipse.rdf4j.model.impl.SimpleValueFactory; +import org.eclipse.rdf4j.model.vocabulary.FOAF; +import org.eclipse.rdf4j.model.vocabulary.RDF; +import org.eclipse.rdf4j.query.BindingSet; +import org.eclipse.rdf4j.repository.sail.SailRepository; +import org.eclipse.rdf4j.repository.sail.SailRepositoryConnection; +import org.eclipse.rdf4j.sail.memory.MemoryStore; +import org.eclipse.rdf4j.sail.shacl.ShaclSailConnection; +import org.eclipse.rdf4j.sail.shacl.Utils; +import org.openjdk.jmh.annotations.Benchmark; +import org.openjdk.jmh.annotations.BenchmarkMode; +import org.openjdk.jmh.annotations.Fork; +import org.openjdk.jmh.annotations.Level; +import org.openjdk.jmh.annotations.Measurement; +import org.openjdk.jmh.annotations.Mode; +import org.openjdk.jmh.annotations.OutputTimeUnit; +import org.openjdk.jmh.annotations.Scope; +import org.openjdk.jmh.annotations.Setup; +import org.openjdk.jmh.annotations.State; +import org.openjdk.jmh.annotations.TearDown; +import org.openjdk.jmh.annotations.Warmup; +import org.slf4j.LoggerFactory; + +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.TimeUnit; +import java.util.stream.Stream; + +/** + * @author Håvard Ottestad + */ +@State(Scope.Benchmark) +@Warmup(iterations = 20) +@BenchmarkMode({Mode.AverageTime}) +@Fork(value = 1, jvmArgs = {"-Xms8G", "-Xmx8G", "-Xmn4G", "-XX:+UseSerialGC"}) +@Measurement(iterations = 10) +@OutputTimeUnit(TimeUnit.MILLISECONDS) +public class ClassBenchmarkEmpty { + + + private List> allStatements; + + @Setup(Level.Invocation) + public void setUp() { + Logger root = (Logger) LoggerFactory.getLogger(ShaclSailConnection.class.getName()); + root.setLevel(ch.qos.logback.classic.Level.INFO); + + allStatements = new ArrayList<>(10); + + + SimpleValueFactory vf = SimpleValueFactory.getInstance(); + + for (int j = 0; j < 10; j++) { + List statements = new ArrayList<>(101); + allStatements.add(statements); + for (int i = 0; i < 1000; i++) { + statements.add( + vf.createStatement(vf.createIRI("http://example.com/" + i + "_" + j), RDF.TYPE, FOAF.PERSON) + ); + statements.add( + vf.createStatement(vf.createIRI("http://example.com/" + i + "_" + j), FOAF.KNOWS, vf.createIRI("http://example.com/friend" + i + "_" + j)) + ); + statements.add( + vf.createStatement(vf.createIRI("http://example.com/friend" + i + "_" + j), RDF.TYPE, FOAF.PERSON) + ); + } + } + System.gc(); + + } + + @TearDown(Level.Iteration) + public void tearDown() { + allStatements.clear(); + } + + + @Benchmark + public void shacl() throws Exception { + + SailRepository repository = new SailRepository(Utils.getInitializedShaclSail("shaclClassBenchmark.ttl")); + + + try (SailRepositoryConnection connection = repository.getConnection()) { + connection.begin(); + connection.commit(); + } + + try (SailRepositoryConnection connection = repository.getConnection()) { + for (List statements : allStatements) { + connection.begin(); + connection.add(statements); + connection.commit(); + } + } + + } + + + @Benchmark + public void noShacl() { + + SailRepository repository = new SailRepository(new MemoryStore()); + + repository.init(); + + try (SailRepositoryConnection connection = repository.getConnection()) { + connection.begin(); + connection.commit(); + } + try (SailRepositoryConnection connection = repository.getConnection()) { + for (List statements : allStatements) { + connection.begin(); + connection.add(statements); + connection.commit(); + } + } + + } + + + @Benchmark + public void sparqlInsteadOfShacl() { + + SailRepository repository = new SailRepository(new MemoryStore()); + + repository.init(); + + try (SailRepositoryConnection connection = repository.getConnection()) { + connection.begin(); + connection.commit(); + } + try (SailRepositoryConnection connection = repository.getConnection()) { + for (List statements : allStatements) { + connection.begin(); + connection.add(statements); + try (Stream stream = Iterations.stream(connection.prepareTupleQuery("select * where {?a a <" + FOAF.PERSON + ">. ?a <" + FOAF.KNOWS + "> ?c. FILTER(NOT EXISTS{?c a <"+FOAF.PERSON+">})}").evaluate())) { + stream.forEach(System.out::println); + } + connection.commit(); + } + } + + } + +} diff --git a/shacl/src/test/java/org/eclipse/rdf4j/sail/shacl/benchmark/ComplexBenchmark.java b/shacl/src/test/java/org/eclipse/rdf4j/sail/shacl/benchmark/ComplexBenchmark.java index c67e9dafa..280cb140b 100644 --- a/shacl/src/test/java/org/eclipse/rdf4j/sail/shacl/benchmark/ComplexBenchmark.java +++ b/shacl/src/test/java/org/eclipse/rdf4j/sail/shacl/benchmark/ComplexBenchmark.java @@ -45,11 +45,11 @@ * @author Håvard Ottestad */ @State(Scope.Benchmark) -@Warmup(iterations = 10) +@Warmup(iterations = 20) @BenchmarkMode({Mode.AverageTime}) @Fork(value = 1, jvmArgs = {"-Xms8G", "-Xmx8G", "-Xmn4G", "-XX:+UseSerialGC"}) //@Fork(value = 1, jvmArgs = {"-Xms8G", "-Xmx8G", "-Xmn4G", "-XX:+UseSerialGC", "-XX:+UnlockCommercialFeatures", "-XX:StartFlightRecording=delay=15s,duration=120s,filename=recording.jfr,settings=ProfilingAggressive.jfc", "-XX:FlightRecorderOptions=samplethreads=true,stackdepth=1024", "-XX:+UnlockDiagnosticVMOptions", "-XX:+DebugNonSafepoints"}) -@Measurement(iterations = 30) +@Measurement(iterations = 10) @OutputTimeUnit(TimeUnit.MILLISECONDS) public class ComplexBenchmark { diff --git a/shacl/src/test/java/org/eclipse/rdf4j/sail/shacl/benchmark/DatatypeBenchmarkEmpty.java b/shacl/src/test/java/org/eclipse/rdf4j/sail/shacl/benchmark/DatatypeBenchmarkEmpty.java index 687d8b166..0e168ce74 100644 --- a/shacl/src/test/java/org/eclipse/rdf4j/sail/shacl/benchmark/DatatypeBenchmarkEmpty.java +++ b/shacl/src/test/java/org/eclipse/rdf4j/sail/shacl/benchmark/DatatypeBenchmarkEmpty.java @@ -8,15 +8,19 @@ package org.eclipse.rdf4j.sail.shacl.benchmark; +import ch.qos.logback.classic.Logger; import org.eclipse.rdf4j.IsolationLevels; +import org.eclipse.rdf4j.common.iteration.Iterations; import org.eclipse.rdf4j.model.Statement; import org.eclipse.rdf4j.model.impl.SimpleValueFactory; import org.eclipse.rdf4j.model.vocabulary.FOAF; import org.eclipse.rdf4j.model.vocabulary.RDF; import org.eclipse.rdf4j.model.vocabulary.RDFS; +import org.eclipse.rdf4j.query.BindingSet; import org.eclipse.rdf4j.repository.sail.SailRepository; import org.eclipse.rdf4j.repository.sail.SailRepositoryConnection; import org.eclipse.rdf4j.sail.memory.MemoryStore; +import org.eclipse.rdf4j.sail.shacl.ShaclSailConnection; import org.eclipse.rdf4j.sail.shacl.Utils; import org.openjdk.jmh.annotations.Benchmark; import org.openjdk.jmh.annotations.BenchmarkMode; @@ -30,20 +34,22 @@ import org.openjdk.jmh.annotations.State; import org.openjdk.jmh.annotations.TearDown; import org.openjdk.jmh.annotations.Warmup; +import org.slf4j.LoggerFactory; import java.util.ArrayList; import java.util.List; import java.util.concurrent.TimeUnit; +import java.util.stream.Stream; /** * @author Håvard Ottestad */ @State(Scope.Benchmark) -@Warmup(iterations = 10) +@Warmup(iterations = 20) @BenchmarkMode({Mode.AverageTime}) @Fork(value = 1, jvmArgs = {"-Xms8G", "-Xmx8G", "-Xmn4G", "-XX:+UseSerialGC"}) //@Fork(value = 1, jvmArgs = {"-Xms8G", "-Xmx8G", "-Xmn4G", "-XX:+UseSerialGC", "-XX:+UnlockCommercialFeatures", "-XX:StartFlightRecording=delay=5s,duration=120s,filename=recording.jfr,settings=profile", "-XX:FlightRecorderOptions=samplethreads=true,stackdepth=1024", "-XX:+UnlockDiagnosticVMOptions", "-XX:+DebugNonSafepoints"}) -@Measurement(iterations = 20) +@Measurement(iterations = 10) @OutputTimeUnit(TimeUnit.MILLISECONDS) public class DatatypeBenchmarkEmpty { @@ -55,6 +61,8 @@ public class DatatypeBenchmarkEmpty { @Setup(Level.Iteration) public void setUp() { + Logger root = (Logger) LoggerFactory.getLogger(ShaclSailConnection.class.getName()); + root.setLevel(ch.qos.logback.classic.Level.INFO); allStatements = new ArrayList<>(NUMBER_OF_TRANSACTIONS); @@ -131,31 +139,31 @@ public void noShacl() { repository.shutDown(); } -// -// -// @Benchmark -// public void sparqlInsteadOfShacl() { -// -// SailRepository repository = new SailRepository(new MemoryStore()); -// -// repository.init(); -// -// try (SailRepositoryConnection connection = repository.getConnection()) { -// connection.begin(IsolationLevels.SNAPSHOT); -// connection.commit(); -// } -// try (SailRepositoryConnection connection = repository.getConnection()) { -// for (List statements : allStatements) { -// connection.begin(IsolationLevels.SNAPSHOT); -// connection.add(statements); -// try (Stream stream = Iterations.stream(connection.prepareTupleQuery("select * where {?a a <" + RDFS.RESOURCE + ">; <" + FOAF.AGE + "> ?age. FILTER(datatype(?age) != )}").evaluate())) { -// stream.forEach(System.out::println); -// } -// connection.commit(); -// } -// } -// -// } + + + @Benchmark + public void sparqlInsteadOfShacl() { + + SailRepository repository = new SailRepository(new MemoryStore()); + + repository.init(); + + try (SailRepositoryConnection connection = repository.getConnection()) { + connection.begin(IsolationLevels.SNAPSHOT); + connection.commit(); + } + try (SailRepositoryConnection connection = repository.getConnection()) { + for (List statements : allStatements) { + connection.begin(IsolationLevels.SNAPSHOT); + connection.add(statements); + try (Stream stream = Iterations.stream(connection.prepareTupleQuery("select * where {?a a <" + RDFS.RESOURCE + ">; <" + FOAF.AGE + "> ?age. FILTER(datatype(?age) != )}").evaluate())) { + stream.forEach(System.out::println); + } + connection.commit(); + } + } + + } } diff --git a/shacl/src/test/java/org/eclipse/rdf4j/sail/shacl/benchmark/DatatypeBenchmarkLinear.java b/shacl/src/test/java/org/eclipse/rdf4j/sail/shacl/benchmark/DatatypeBenchmarkLinear.java index 7315d129d..587bd2d4a 100644 --- a/shacl/src/test/java/org/eclipse/rdf4j/sail/shacl/benchmark/DatatypeBenchmarkLinear.java +++ b/shacl/src/test/java/org/eclipse/rdf4j/sail/shacl/benchmark/DatatypeBenchmarkLinear.java @@ -8,6 +8,7 @@ package org.eclipse.rdf4j.sail.shacl.benchmark; +import ch.qos.logback.classic.Logger; import org.eclipse.rdf4j.IsolationLevels; import org.eclipse.rdf4j.model.Statement; import org.eclipse.rdf4j.model.impl.SimpleValueFactory; @@ -16,6 +17,8 @@ import org.eclipse.rdf4j.model.vocabulary.RDFS; import org.eclipse.rdf4j.repository.sail.SailRepository; import org.eclipse.rdf4j.repository.sail.SailRepositoryConnection; +import org.eclipse.rdf4j.sail.memory.MemoryStore; +import org.eclipse.rdf4j.sail.shacl.ShaclSailConnection; import org.eclipse.rdf4j.sail.shacl.Utils; import org.openjdk.jmh.annotations.Benchmark; import org.openjdk.jmh.annotations.BenchmarkMode; @@ -30,6 +33,7 @@ import org.openjdk.jmh.annotations.State; import org.openjdk.jmh.annotations.TearDown; import org.openjdk.jmh.annotations.Warmup; +import org.slf4j.LoggerFactory; import java.util.ArrayList; import java.util.List; @@ -39,16 +43,15 @@ * @author Håvard Ottestad */ @State(Scope.Benchmark) -@Warmup(iterations = 10) +@Warmup(iterations = 20) @BenchmarkMode({Mode.AverageTime}) -@Fork(value = 1, jvmArgs = {"-Xms4G", "-Xmx4G", "-Xmn2G", "-XX:+UseSerialGC", "-XX:+UnlockCommercialFeatures", "-XX:StartFlightRecording=delay=5s,duration=60s,filename=recording.jfr,settings=profile", "-XX:FlightRecorderOptions=samplethreads=true,stackdepth=1024", "-XX:+UnlockDiagnosticVMOptions", "-XX:+DebugNonSafepoints"}) -//@Fork(value = 1, jvmArgs = {"-Xms4G", "-Xmx4G"}) -@Measurement(iterations = 30) +//@Fork(value = 1, jvmArgs = {"-Xms4G", "-Xmx4G", "-Xmn2G", "-XX:+UseSerialGC", "-XX:+UnlockCommercialFeatures", "-XX:StartFlightRecording=delay=5s,duration=60s,filename=recording.jfr,settings=profile", "-XX:FlightRecorderOptions=samplethreads=true,stackdepth=1024", "-XX:+UnlockDiagnosticVMOptions", "-XX:+DebugNonSafepoints"}) +@Fork(value = 1, jvmArgs = {"-Xms8G", "-Xmx8G", "-Xmn4G", "-XX:+UseSerialGC"}) +@Measurement(iterations = 10) @OutputTimeUnit(TimeUnit.MILLISECONDS) public class DatatypeBenchmarkLinear { -// @Param({"1", "10", "100"}) - @Param({"100"}) + @Param({"1", "10", "100"}) public int NUMBER_OF_TRANSACTIONS = 10; private static final int STATEMENTS_PER_TRANSACTION = 100; @@ -57,6 +60,8 @@ public class DatatypeBenchmarkLinear { @Setup(Level.Iteration) public void setUp() { + Logger root = (Logger) LoggerFactory.getLogger(ShaclSailConnection.class.getName()); + root.setLevel(ch.qos.logback.classic.Level.INFO); allStatements = new ArrayList<>(NUMBER_OF_TRANSACTIONS); @@ -106,26 +111,26 @@ public void shacl() throws Exception { } -// @Benchmark -// public void noShacl() { -// -// SailRepository repository = new SailRepository(new MemoryStore()); -// -// repository.init(); -// -// try (SailRepositoryConnection connection = repository.getConnection()) { -// connection.begin(IsolationLevels.SNAPSHOT); -// connection.commit(); -// } -// try (SailRepositoryConnection connection = repository.getConnection()) { -// for (List statements : allStatements) { -// connection.begin(IsolationLevels.SNAPSHOT); -// connection.add(statements); -// connection.commit(); -// } -// } -// -// } + @Benchmark + public void noShacl() { + + SailRepository repository = new SailRepository(new MemoryStore()); + + repository.init(); + + try (SailRepositoryConnection connection = repository.getConnection()) { + connection.begin(IsolationLevels.SNAPSHOT); + connection.commit(); + } + try (SailRepositoryConnection connection = repository.getConnection()) { + for (List statements : allStatements) { + connection.begin(IsolationLevels.SNAPSHOT); + connection.add(statements); + connection.commit(); + } + } + + } diff --git a/shacl/src/test/java/org/eclipse/rdf4j/sail/shacl/benchmark/DatatypeBenchmarkPrefilled.java b/shacl/src/test/java/org/eclipse/rdf4j/sail/shacl/benchmark/DatatypeBenchmarkPrefilled.java index 95c9021da..7893a5443 100644 --- a/shacl/src/test/java/org/eclipse/rdf4j/sail/shacl/benchmark/DatatypeBenchmarkPrefilled.java +++ b/shacl/src/test/java/org/eclipse/rdf4j/sail/shacl/benchmark/DatatypeBenchmarkPrefilled.java @@ -8,6 +8,7 @@ package org.eclipse.rdf4j.sail.shacl.benchmark; +import ch.qos.logback.classic.Logger; import org.eclipse.rdf4j.common.iteration.Iterations; import org.eclipse.rdf4j.model.Statement; import org.eclipse.rdf4j.model.impl.SimpleValueFactory; @@ -19,6 +20,7 @@ import org.eclipse.rdf4j.repository.sail.SailRepositoryConnection; import org.eclipse.rdf4j.sail.memory.MemoryStore; import org.eclipse.rdf4j.sail.shacl.ShaclSail; +import org.eclipse.rdf4j.sail.shacl.ShaclSailConnection; import org.eclipse.rdf4j.sail.shacl.Utils; import org.openjdk.jmh.annotations.Benchmark; import org.openjdk.jmh.annotations.BenchmarkMode; @@ -32,6 +34,7 @@ import org.openjdk.jmh.annotations.State; import org.openjdk.jmh.annotations.TearDown; import org.openjdk.jmh.annotations.Warmup; +import org.slf4j.LoggerFactory; import java.util.ArrayList; import java.util.List; @@ -42,9 +45,9 @@ * @author Håvard Ottestad */ @State(Scope.Benchmark) -@Warmup(iterations = 10) +@Warmup(iterations = 20) @BenchmarkMode({Mode.AverageTime}) -@Fork(value = 1, jvmArgs = {"-Xms4G", "-Xmx4G", "-Xmn2G"}) +@Fork(value = 1, jvmArgs = {"-Xms8G", "-Xmx8G", "-Xmn4G", "-XX:+UseSerialGC"}) @Measurement(iterations = 10) @OutputTimeUnit(TimeUnit.MILLISECONDS) public class DatatypeBenchmarkPrefilled { @@ -52,13 +55,21 @@ public class DatatypeBenchmarkPrefilled { private List> allStatements; - SailRepository shaclRepo; - SailRepository memoryStoreRepo; - SailRepository sparqlQueryMemoryStoreRepo; + private SailRepository shaclRepo; + private SailRepository memoryStoreRepo; + private SailRepository sparqlQueryMemoryStoreRepo; @Setup(Level.Invocation) public void setUp() throws Exception { + Logger root = (Logger) LoggerFactory.getLogger(ShaclSailConnection.class.getName()); + root.setLevel(ch.qos.logback.classic.Level.INFO); + + if(shaclRepo != null) shaclRepo.shutDown(); + if(memoryStoreRepo != null) memoryStoreRepo.shutDown(); + if(sparqlQueryMemoryStoreRepo != null) sparqlQueryMemoryStoreRepo.shutDown(); + + allStatements = new ArrayList<>(10); SimpleValueFactory vf = SimpleValueFactory.getInstance(); diff --git a/shacl/src/test/java/org/eclipse/rdf4j/sail/shacl/benchmark/Main.java b/shacl/src/test/java/org/eclipse/rdf4j/sail/shacl/benchmark/Main.java index 62f4a7822..fa94d5b53 100644 --- a/shacl/src/test/java/org/eclipse/rdf4j/sail/shacl/benchmark/Main.java +++ b/shacl/src/test/java/org/eclipse/rdf4j/sail/shacl/benchmark/Main.java @@ -20,16 +20,8 @@ public class Main { public static void main(String[] args) throws RunnerException { Options opt = new OptionsBuilder() - .include("MinCount") -// .include(MinCountBenchmark.class.getSimpleName()+".noShacl") - -// .include(MinCountBenchmarkPrefilled.class.getSimpleName()) -// .include(MinCountPrefilledVsEmptyBenchmark.class.getSimpleName()+"..shaclPrefilled$") -// .include(MinCountPrefilledVsEmptyBenchmark.class.getSimpleName()+"..shaclEmpty$") - - .warmupIterations(10) - .measurementIterations(10) - .forks(1) + .include("") + //.addProfiler("stack", "lines=20;period=1;top=20") .build(); diff --git a/shacl/src/test/java/org/eclipse/rdf4j/sail/shacl/benchmark/MaxCountBenchmarkEmpty.java b/shacl/src/test/java/org/eclipse/rdf4j/sail/shacl/benchmark/MaxCountBenchmarkEmpty.java new file mode 100644 index 000000000..f9b4535f5 --- /dev/null +++ b/shacl/src/test/java/org/eclipse/rdf4j/sail/shacl/benchmark/MaxCountBenchmarkEmpty.java @@ -0,0 +1,182 @@ +/******************************************************************************* + * Copyright (c) 2018 Eclipse RDF4J contributors. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Distribution License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/org/documents/edl-v10.php. + *******************************************************************************/ + +package org.eclipse.rdf4j.sail.shacl.benchmark; + +import ch.qos.logback.classic.Logger; +import org.eclipse.rdf4j.common.iteration.Iterations; +import org.eclipse.rdf4j.model.Statement; +import org.eclipse.rdf4j.model.impl.SimpleValueFactory; +import org.eclipse.rdf4j.model.vocabulary.RDF; +import org.eclipse.rdf4j.model.vocabulary.RDFS; +import org.eclipse.rdf4j.query.BindingSet; +import org.eclipse.rdf4j.repository.sail.SailRepository; +import org.eclipse.rdf4j.repository.sail.SailRepositoryConnection; +import org.eclipse.rdf4j.sail.memory.MemoryStore; +import org.eclipse.rdf4j.sail.shacl.ShaclSailConnection; +import org.eclipse.rdf4j.sail.shacl.Utils; +import org.openjdk.jmh.annotations.Benchmark; +import org.openjdk.jmh.annotations.BenchmarkMode; +import org.openjdk.jmh.annotations.Fork; +import org.openjdk.jmh.annotations.Level; +import org.openjdk.jmh.annotations.Measurement; +import org.openjdk.jmh.annotations.Mode; +import org.openjdk.jmh.annotations.OutputTimeUnit; +import org.openjdk.jmh.annotations.Scope; +import org.openjdk.jmh.annotations.Setup; +import org.openjdk.jmh.annotations.State; +import org.openjdk.jmh.annotations.TearDown; +import org.openjdk.jmh.annotations.Warmup; +import org.slf4j.LoggerFactory; + +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.TimeUnit; +import java.util.stream.Stream; + +/** + * @author Håvard Ottestad + */ +@State(Scope.Benchmark) +@Warmup(iterations = 20) +@BenchmarkMode({Mode.AverageTime}) +@Fork(value = 1, jvmArgs = {"-Xms8G", "-Xmx8G", "-Xmn4G", "-XX:+UseSerialGC"}) +@Measurement(iterations = 10) +@OutputTimeUnit(TimeUnit.MILLISECONDS) +public class MaxCountBenchmarkEmpty { + + + private List> allStatements; + + @Setup(Level.Invocation) + public void setUp() { + Logger root = (Logger) LoggerFactory.getLogger(ShaclSailConnection.class.getName()); + root.setLevel(ch.qos.logback.classic.Level.INFO); + + allStatements = new ArrayList<>(10); + + + SimpleValueFactory vf = SimpleValueFactory.getInstance(); + + for (int j = 0; j < 10; j++) { + List statements = new ArrayList<>(101); + allStatements.add(statements); + for (int i = 0; i < 1000; i++) { + statements.add( + vf.createStatement(vf.createIRI("http://example.com/" + i + "_" + j), RDF.TYPE, RDFS.RESOURCE) + ); + statements.add( + vf.createStatement(vf.createIRI("http://example.com/" + i + "_" + j), RDFS.LABEL, vf.createLiteral("label" + i)) + ); + } + } + System.gc(); + + } + + @TearDown(Level.Iteration) + public void tearDown() { + allStatements.clear(); + } + + + @Benchmark + public void shacl() throws Exception { + + SailRepository repository = new SailRepository(Utils.getInitializedShaclSail("shaclMaxCountBenchmark.ttl")); + + + try (SailRepositoryConnection connection = repository.getConnection()) { + connection.begin(); + connection.commit(); + } + + try (SailRepositoryConnection connection = repository.getConnection()) { + for (List statements : allStatements) { + connection.begin(); + connection.add(statements); + connection.commit(); + } + } + + } + + + @Benchmark + public void noShacl() { + + SailRepository repository = new SailRepository(new MemoryStore()); + + repository.init(); + + try (SailRepositoryConnection connection = repository.getConnection()) { + connection.begin(); + connection.commit(); + } + try (SailRepositoryConnection connection = repository.getConnection()) { + for (List statements : allStatements) { + connection.begin(); + connection.add(statements); + connection.commit(); + } + } + + } + + + @Benchmark + public void sparqlInsteadOfShacl() { + + SailRepository repository = new SailRepository(new MemoryStore()); + + repository.init(); + + try (SailRepositoryConnection connection = repository.getConnection()) { + connection.begin(); + connection.commit(); + } + try (SailRepositoryConnection connection = repository.getConnection()) { + for (List statements : allStatements) { + connection.begin(); + connection.add(statements); + try (Stream stream = Iterations.stream(connection.prepareTupleQuery("select * where {?a a <" + RDFS.RESOURCE + ">. ?a <" + RDFS.LABEL + "> ?c, ?d. FILTER(?c != ?d)}").evaluate())) { + stream.forEach(System.out::println); + } + connection.commit(); + } + } + + } + + @Benchmark + public void sparqlGroupByInsteadOfShacl() { + + SailRepository repository = new SailRepository(new MemoryStore()); + + repository.init(); + + try (SailRepositoryConnection connection = repository.getConnection()) { + connection.begin(); + connection.commit(); + } + try (SailRepositoryConnection connection = repository.getConnection()) { + for (List statements : allStatements) { + connection.begin(); + connection.add(statements); + try (Stream stream = Iterations.stream(connection.prepareTupleQuery("select ?a (count(?c) as ?count) where {?a a <" + RDFS.RESOURCE + ">. ?a <" + RDFS.LABEL + "> ?c} group by ?a having(?count > 1)").evaluate())) { + stream.forEach(System.out::println); + } + connection.commit(); + } + } + + } + + + +} diff --git a/shacl/src/test/java/org/eclipse/rdf4j/sail/shacl/benchmark/MinCountBenchmarkEmpty.java b/shacl/src/test/java/org/eclipse/rdf4j/sail/shacl/benchmark/MinCountBenchmarkEmpty.java index dfbadaef1..99f86398e 100644 --- a/shacl/src/test/java/org/eclipse/rdf4j/sail/shacl/benchmark/MinCountBenchmarkEmpty.java +++ b/shacl/src/test/java/org/eclipse/rdf4j/sail/shacl/benchmark/MinCountBenchmarkEmpty.java @@ -8,6 +8,7 @@ package org.eclipse.rdf4j.sail.shacl.benchmark; +import ch.qos.logback.classic.Logger; import org.eclipse.rdf4j.common.iteration.Iterations; import org.eclipse.rdf4j.model.Statement; import org.eclipse.rdf4j.model.impl.SimpleValueFactory; @@ -17,6 +18,7 @@ import org.eclipse.rdf4j.repository.sail.SailRepository; import org.eclipse.rdf4j.repository.sail.SailRepositoryConnection; import org.eclipse.rdf4j.sail.memory.MemoryStore; +import org.eclipse.rdf4j.sail.shacl.ShaclSailConnection; import org.eclipse.rdf4j.sail.shacl.Utils; import org.openjdk.jmh.annotations.Benchmark; import org.openjdk.jmh.annotations.BenchmarkMode; @@ -30,6 +32,7 @@ import org.openjdk.jmh.annotations.State; import org.openjdk.jmh.annotations.TearDown; import org.openjdk.jmh.annotations.Warmup; +import org.slf4j.LoggerFactory; import java.util.ArrayList; import java.util.List; @@ -40,9 +43,9 @@ * @author Håvard Ottestad */ @State(Scope.Benchmark) -@Warmup(iterations = 10) +@Warmup(iterations = 20) @BenchmarkMode({Mode.AverageTime}) -@Fork(value = 1, jvmArgs = {"-Xms4G", "-Xmx4G", "-Xmn2G"}) +@Fork(value = 1, jvmArgs = {"-Xms8G", "-Xmx8G", "-Xmn4G", "-XX:+UseSerialGC"}) @Measurement(iterations = 10) @OutputTimeUnit(TimeUnit.MILLISECONDS) public class MinCountBenchmarkEmpty { @@ -52,8 +55,8 @@ public class MinCountBenchmarkEmpty { @Setup(Level.Invocation) public void setUp() { - - + Logger root = (Logger) LoggerFactory.getLogger(ShaclSailConnection.class.getName()); + root.setLevel(ch.qos.logback.classic.Level.INFO); allStatements = new ArrayList<>(10); @@ -63,7 +66,7 @@ public void setUp() { for (int j = 0; j < 10; j++) { List statements = new ArrayList<>(101); allStatements.add(statements); - for (int i = 0; i < 100; i++) { + for (int i = 0; i < 1000; i++) { statements.add( vf.createStatement(vf.createIRI("http://example.com/" + i + "_" + j), RDF.TYPE, RDFS.RESOURCE) ); diff --git a/shacl/src/test/java/org/eclipse/rdf4j/sail/shacl/benchmark/MinCountBenchmarkPrefilled.java b/shacl/src/test/java/org/eclipse/rdf4j/sail/shacl/benchmark/MinCountBenchmarkPrefilled.java index fb058163d..2e4ab7bc7 100644 --- a/shacl/src/test/java/org/eclipse/rdf4j/sail/shacl/benchmark/MinCountBenchmarkPrefilled.java +++ b/shacl/src/test/java/org/eclipse/rdf4j/sail/shacl/benchmark/MinCountBenchmarkPrefilled.java @@ -8,6 +8,7 @@ package org.eclipse.rdf4j.sail.shacl.benchmark; +import ch.qos.logback.classic.Logger; import org.eclipse.rdf4j.common.iteration.Iterations; import org.eclipse.rdf4j.model.Statement; import org.eclipse.rdf4j.model.impl.SimpleValueFactory; @@ -18,6 +19,7 @@ import org.eclipse.rdf4j.repository.sail.SailRepositoryConnection; import org.eclipse.rdf4j.sail.memory.MemoryStore; import org.eclipse.rdf4j.sail.shacl.ShaclSail; +import org.eclipse.rdf4j.sail.shacl.ShaclSailConnection; import org.eclipse.rdf4j.sail.shacl.Utils; import org.openjdk.jmh.annotations.Benchmark; import org.openjdk.jmh.annotations.BenchmarkMode; @@ -31,6 +33,7 @@ import org.openjdk.jmh.annotations.State; import org.openjdk.jmh.annotations.TearDown; import org.openjdk.jmh.annotations.Warmup; +import org.slf4j.LoggerFactory; import java.util.ArrayList; import java.util.List; @@ -41,9 +44,9 @@ * @author Håvard Ottestad */ @State(Scope.Benchmark) -@Warmup(iterations = 10) +@Warmup(iterations = 20) @BenchmarkMode({Mode.AverageTime}) -@Fork(value = 1, jvmArgs = {"-Xms4G", "-Xmx4G", "-Xmn2G"}) +@Fork(value = 1, jvmArgs = {"-Xms8G", "-Xmx8G", "-Xmn4G", "-XX:+UseSerialGC"}) @Measurement(iterations = 10) @OutputTimeUnit(TimeUnit.MILLISECONDS) public class MinCountBenchmarkPrefilled { @@ -51,13 +54,21 @@ public class MinCountBenchmarkPrefilled { private List> allStatements; - SailRepository shaclRepo; - SailRepository memoryStoreRepo; - SailRepository sparqlQueryMemoryStoreRepo; + private SailRepository shaclRepo; + private SailRepository memoryStoreRepo; + private SailRepository sparqlQueryMemoryStoreRepo; @Setup(Level.Invocation) public void setUp() throws Exception { + Logger root = (Logger) LoggerFactory.getLogger(ShaclSailConnection.class.getName()); + root.setLevel(ch.qos.logback.classic.Level.INFO); + + if(shaclRepo != null) shaclRepo.shutDown(); + if(memoryStoreRepo != null) memoryStoreRepo.shutDown(); + if(sparqlQueryMemoryStoreRepo != null) sparqlQueryMemoryStoreRepo.shutDown(); + + allStatements = new ArrayList<>(10); SimpleValueFactory vf = SimpleValueFactory.getInstance(); @@ -65,7 +76,7 @@ public void setUp() throws Exception { for (int j = 0; j < 10; j++) { List statements = new ArrayList<>(101); allStatements.add(statements); - for (int i = 0; i < 100; i++) { + for (int i = 0; i < 1000; i++) { statements.add( vf.createStatement(vf.createIRI("http://example.com/" + i + "_" + j), RDF.TYPE, RDFS.RESOURCE) ); diff --git a/shacl/src/test/java/org/eclipse/rdf4j/sail/shacl/benchmark/MinCountPrefilledVsEmptyBenchmark.java b/shacl/src/test/java/org/eclipse/rdf4j/sail/shacl/benchmark/MinCountPrefilledVsEmptyBenchmark.java index b05676b4b..d12e3320e 100644 --- a/shacl/src/test/java/org/eclipse/rdf4j/sail/shacl/benchmark/MinCountPrefilledVsEmptyBenchmark.java +++ b/shacl/src/test/java/org/eclipse/rdf4j/sail/shacl/benchmark/MinCountPrefilledVsEmptyBenchmark.java @@ -8,6 +8,7 @@ package org.eclipse.rdf4j.sail.shacl.benchmark; +import ch.qos.logback.classic.Logger; import org.eclipse.rdf4j.model.Statement; import org.eclipse.rdf4j.model.impl.SimpleValueFactory; import org.eclipse.rdf4j.model.vocabulary.RDF; @@ -15,6 +16,7 @@ import org.eclipse.rdf4j.repository.sail.SailRepository; import org.eclipse.rdf4j.repository.sail.SailRepositoryConnection; import org.eclipse.rdf4j.sail.shacl.ShaclSail; +import org.eclipse.rdf4j.sail.shacl.ShaclSailConnection; import org.eclipse.rdf4j.sail.shacl.Utils; import org.openjdk.jmh.annotations.Benchmark; import org.openjdk.jmh.annotations.BenchmarkMode; @@ -28,6 +30,7 @@ import org.openjdk.jmh.annotations.State; import org.openjdk.jmh.annotations.TearDown; import org.openjdk.jmh.annotations.Warmup; +import org.slf4j.LoggerFactory; import java.util.ArrayList; import java.util.List; @@ -37,9 +40,9 @@ * @author Håvard Ottestad */ @State(Scope.Benchmark) -@Warmup(iterations = 10) +@Warmup(iterations = 20) @BenchmarkMode({Mode.AverageTime}) -@Fork(value = 1, jvmArgs = {"-Xms4G", "-Xmx4G", "-Xmn2G"}) +@Fork(value = 1, jvmArgs = {"-Xms8G", "-Xmx8G", "-Xmn4G", "-XX:+UseSerialGC"}) @Measurement(iterations = 10) @OutputTimeUnit(TimeUnit.MILLISECONDS) public class MinCountPrefilledVsEmptyBenchmark { @@ -51,15 +54,19 @@ public class MinCountPrefilledVsEmptyBenchmark { @Setup(Level.Invocation) public void setUp() throws Exception { + Logger root = (Logger) LoggerFactory.getLogger(ShaclSailConnection.class.getName()); + root.setLevel(ch.qos.logback.classic.Level.INFO); + allStatements = new ArrayList<>(10); + if(shaclRepo != null) shaclRepo.shutDown(); SimpleValueFactory vf = SimpleValueFactory.getInstance(); for (int j = 0; j < 10; j++) { List statements = new ArrayList<>(101); allStatements.add(statements); - for (int i = 0; i < 100; i++) { + for (int i = 0; i < 1000; i++) { statements.add( vf.createStatement(vf.createIRI("http://example.com/" + i + "_" + j), RDF.TYPE, RDFS.RESOURCE) ); diff --git a/shacl/src/test/java/org/eclipse/rdf4j/sail/shacl/config/ShaclSailConfigTest.java b/shacl/src/test/java/org/eclipse/rdf4j/sail/shacl/config/ShaclSailConfigTest.java index 05ec23ec3..be117ce9c 100644 --- a/shacl/src/test/java/org/eclipse/rdf4j/sail/shacl/config/ShaclSailConfigTest.java +++ b/shacl/src/test/java/org/eclipse/rdf4j/sail/shacl/config/ShaclSailConfigTest.java @@ -45,7 +45,7 @@ public void setUp() throws Exception { @Test public void defaultsCorrectlySet() { - assertThat(subject.isParallelValidation()).isTrue(); + assertThat(subject.isParallelValidation()).isFalse(); assertThat(subject.isUndefinedTargetValidatesAllSubjects()).isFalse(); assertThat(subject.isLogValidationPlans()).isFalse(); assertThat(subject.isLogValidationViolations()).isFalse(); diff --git a/shacl/src/test/resources/shaclClassBenchmark.ttl b/shacl/src/test/resources/shaclClassBenchmark.ttl new file mode 100644 index 000000000..abd6c6faa --- /dev/null +++ b/shacl/src/test/resources/shaclClassBenchmark.ttl @@ -0,0 +1,18 @@ +@base . +@prefix ex: . +@prefix owl: . +@prefix rdf: . +@prefix rdfs: . +@prefix sh: . +@prefix xsd: . +@prefix foaf: . + +ex:PersonShape + a sh:NodeShape ; + sh:targetClass foaf:Person ; + sh:property ex:PersonShapeProperty . + + +ex:PersonShapeProperty + sh:path foaf:knows ; + sh:class foaf:Person . \ No newline at end of file diff --git a/shacl/src/test/resources/shaclMaxCountBenchmark.ttl b/shacl/src/test/resources/shaclMaxCountBenchmark.ttl new file mode 100644 index 000000000..fc0fb6d74 --- /dev/null +++ b/shacl/src/test/resources/shaclMaxCountBenchmark.ttl @@ -0,0 +1,17 @@ +@base . +@prefix ex: . +@prefix owl: . +@prefix rdf: . +@prefix rdfs: . +@prefix sh: . +@prefix xsd: . + +ex:PersonShape + a sh:NodeShape ; + sh:targetClass rdfs:Resource ; + sh:property ex:PersonShapeProperty . + + +ex:PersonShapeProperty + sh:path rdfs:label ; + sh:maxCount 1 . \ No newline at end of file diff --git a/shacl/src/test/resources/test-cases/class/targetNode/invalid/case1/query1.rq b/shacl/src/test/resources/test-cases/class/targetNode/invalid/case1/query1.rq new file mode 100644 index 000000000..1e1db0745 --- /dev/null +++ b/shacl/src/test/resources/test-cases/class/targetNode/invalid/case1/query1.rq @@ -0,0 +1,13 @@ +PREFIX ex: +PREFIX owl: +PREFIX rdf: +PREFIX rdfs: +PREFIX sh: +PREFIX xsd: + +INSERT DATA { + +ex:validPerson1 a ex:Person ; + ex:knows ex:peter. + +} diff --git a/shacl/src/test/resources/test-cases/class/targetNode/invalid/case2/query1.rq b/shacl/src/test/resources/test-cases/class/targetNode/invalid/case2/query1.rq new file mode 100644 index 000000000..2433dceb5 --- /dev/null +++ b/shacl/src/test/resources/test-cases/class/targetNode/invalid/case2/query1.rq @@ -0,0 +1,12 @@ +PREFIX ex: +PREFIX owl: +PREFIX rdf: +PREFIX rdfs: +PREFIX sh: +PREFIX xsd: + +INSERT DATA { + +ex:validPerson1 ex:knows ex:peter. + +} diff --git a/shacl/src/test/resources/test-cases/class/targetNode/invalid/case2/query2.rq b/shacl/src/test/resources/test-cases/class/targetNode/invalid/case2/query2.rq new file mode 100644 index 000000000..93fb72304 --- /dev/null +++ b/shacl/src/test/resources/test-cases/class/targetNode/invalid/case2/query2.rq @@ -0,0 +1,12 @@ +PREFIX ex: +PREFIX owl: +PREFIX rdf: +PREFIX rdfs: +PREFIX sh: +PREFIX xsd: + +INSERT DATA { + +ex:validPerson1 a ex:Person . + +} diff --git a/shacl/src/test/resources/test-cases/class/targetNode/invalid/case3/query1.rq b/shacl/src/test/resources/test-cases/class/targetNode/invalid/case3/query1.rq new file mode 100644 index 000000000..4fe46ddbe --- /dev/null +++ b/shacl/src/test/resources/test-cases/class/targetNode/invalid/case3/query1.rq @@ -0,0 +1,15 @@ +PREFIX ex: +PREFIX owl: +PREFIX rdf: +PREFIX rdfs: +PREFIX sh: +PREFIX xsd: + +INSERT DATA { + +ex:validPerson1 a ex:Person ; + ex:knows ex:peter. + +ex:peter a ex:Person. + +} diff --git a/shacl/src/test/resources/test-cases/class/targetNode/invalid/case3/query2.rq b/shacl/src/test/resources/test-cases/class/targetNode/invalid/case3/query2.rq new file mode 100644 index 000000000..d6260a23c --- /dev/null +++ b/shacl/src/test/resources/test-cases/class/targetNode/invalid/case3/query2.rq @@ -0,0 +1,12 @@ +PREFIX ex: +PREFIX owl: +PREFIX rdf: +PREFIX rdfs: +PREFIX sh: +PREFIX xsd: + +DELETE DATA { + +ex:peter a ex:Person. + +} diff --git a/shacl/src/test/resources/test-cases/class/targetNode/invalid/case4/query1.rq b/shacl/src/test/resources/test-cases/class/targetNode/invalid/case4/query1.rq new file mode 100644 index 000000000..4fe46ddbe --- /dev/null +++ b/shacl/src/test/resources/test-cases/class/targetNode/invalid/case4/query1.rq @@ -0,0 +1,15 @@ +PREFIX ex: +PREFIX owl: +PREFIX rdf: +PREFIX rdfs: +PREFIX sh: +PREFIX xsd: + +INSERT DATA { + +ex:validPerson1 a ex:Person ; + ex:knows ex:peter. + +ex:peter a ex:Person. + +} diff --git a/shacl/src/test/resources/test-cases/class/targetNode/invalid/case4/query2.rq b/shacl/src/test/resources/test-cases/class/targetNode/invalid/case4/query2.rq new file mode 100644 index 000000000..91340e628 --- /dev/null +++ b/shacl/src/test/resources/test-cases/class/targetNode/invalid/case4/query2.rq @@ -0,0 +1,15 @@ +PREFIX ex: +PREFIX owl: +PREFIX rdf: +PREFIX rdfs: +PREFIX sh: +PREFIX xsd: + +INSERT DATA { + +ex:validPerson1 ex:knows ex:apple. + +ex:apple a ex:Company. + +} + diff --git a/shacl/src/test/resources/test-cases/class/targetNode/invalid/case5/query1.rq b/shacl/src/test/resources/test-cases/class/targetNode/invalid/case5/query1.rq new file mode 100644 index 000000000..326bbd793 --- /dev/null +++ b/shacl/src/test/resources/test-cases/class/targetNode/invalid/case5/query1.rq @@ -0,0 +1,16 @@ +PREFIX ex: +PREFIX owl: +PREFIX rdf: +PREFIX rdfs: +PREFIX sh: +PREFIX xsd: + +INSERT DATA { + +ex:validPerson1 a ex:Person ; + ex:knows ex:peter. + +ex:peter a ex:Person. +ex:steve a ex:Person. + +} diff --git a/shacl/src/test/resources/test-cases/class/targetNode/invalid/case5/query2.rq b/shacl/src/test/resources/test-cases/class/targetNode/invalid/case5/query2.rq new file mode 100644 index 000000000..f41dc5eb4 --- /dev/null +++ b/shacl/src/test/resources/test-cases/class/targetNode/invalid/case5/query2.rq @@ -0,0 +1,19 @@ +PREFIX ex: +PREFIX owl: +PREFIX rdf: +PREFIX rdfs: +PREFIX sh: +PREFIX xsd: + +delete { +ex:steve a ex:Person. + +} + +INSERT { + +ex:validPerson1 ex:knows ex:steve. + + +} + where {?a ?b ?c} \ No newline at end of file diff --git a/shacl/src/test/resources/test-cases/class/targetNode/invalid/case6/query1.rq b/shacl/src/test/resources/test-cases/class/targetNode/invalid/case6/query1.rq new file mode 100644 index 000000000..3cd382042 --- /dev/null +++ b/shacl/src/test/resources/test-cases/class/targetNode/invalid/case6/query1.rq @@ -0,0 +1,15 @@ +PREFIX ex: +PREFIX owl: +PREFIX rdf: +PREFIX rdfs: +PREFIX sh: +PREFIX xsd: + +INSERT DATA { + +ex:validPerson1 a ex:Person ; + ex:knows _:b1. + +_:b1 a ex:Person. + +} diff --git a/shacl/src/test/resources/test-cases/class/targetNode/invalid/case6/query2.rq b/shacl/src/test/resources/test-cases/class/targetNode/invalid/case6/query2.rq new file mode 100644 index 000000000..b541c22f1 --- /dev/null +++ b/shacl/src/test/resources/test-cases/class/targetNode/invalid/case6/query2.rq @@ -0,0 +1,13 @@ +PREFIX ex: +PREFIX owl: +PREFIX rdf: +PREFIX rdfs: +PREFIX sh: +PREFIX xsd: + +delete { + ?b ?c ?d. +} where { + ?a ex:knows ?b. + ?b ?c ?d. +} diff --git a/shacl/src/test/resources/test-cases/class/targetNode/invalid/case7/query1.rq b/shacl/src/test/resources/test-cases/class/targetNode/invalid/case7/query1.rq new file mode 100644 index 000000000..90321287d --- /dev/null +++ b/shacl/src/test/resources/test-cases/class/targetNode/invalid/case7/query1.rq @@ -0,0 +1,13 @@ +PREFIX ex: +PREFIX owl: +PREFIX rdf: +PREFIX rdfs: +PREFIX sh: +PREFIX xsd: + +INSERT DATA { + +ex:validPerson1 a ex:Person ; + ex:knows "peter". + +} diff --git a/shacl/src/test/resources/test-cases/class/targetNode/shacl.ttl b/shacl/src/test/resources/test-cases/class/targetNode/shacl.ttl new file mode 100644 index 000000000..53df706ba --- /dev/null +++ b/shacl/src/test/resources/test-cases/class/targetNode/shacl.ttl @@ -0,0 +1,16 @@ +@base . +@prefix ex: . +@prefix owl: . +@prefix rdf: . +@prefix rdfs: . +@prefix sh: . +@prefix xsd: . + +ex:PersonShape + a sh:NodeShape ; + sh:targetNode ex:validPerson1 ; + sh:property [ + sh:path ex:knows ; + sh:class ex:Person ; + ] . + diff --git a/shacl/src/test/resources/test-cases/class/targetNode/valid/case1/query1.rq b/shacl/src/test/resources/test-cases/class/targetNode/valid/case1/query1.rq new file mode 100644 index 000000000..4fe46ddbe --- /dev/null +++ b/shacl/src/test/resources/test-cases/class/targetNode/valid/case1/query1.rq @@ -0,0 +1,15 @@ +PREFIX ex: +PREFIX owl: +PREFIX rdf: +PREFIX rdfs: +PREFIX sh: +PREFIX xsd: + +INSERT DATA { + +ex:validPerson1 a ex:Person ; + ex:knows ex:peter. + +ex:peter a ex:Person. + +} diff --git a/shacl/src/test/resources/test-cases/class/targetNode/valid/case2/query1.rq b/shacl/src/test/resources/test-cases/class/targetNode/valid/case2/query1.rq new file mode 100644 index 000000000..b7d5f6fee --- /dev/null +++ b/shacl/src/test/resources/test-cases/class/targetNode/valid/case2/query1.rq @@ -0,0 +1,12 @@ +PREFIX ex: +PREFIX owl: +PREFIX rdf: +PREFIX rdfs: +PREFIX sh: +PREFIX xsd: + +INSERT DATA { + +ex:peter a ex:Person. + +} diff --git a/shacl/src/test/resources/test-cases/class/targetNode/valid/case2/query2.rq b/shacl/src/test/resources/test-cases/class/targetNode/valid/case2/query2.rq new file mode 100644 index 000000000..1e1db0745 --- /dev/null +++ b/shacl/src/test/resources/test-cases/class/targetNode/valid/case2/query2.rq @@ -0,0 +1,13 @@ +PREFIX ex: +PREFIX owl: +PREFIX rdf: +PREFIX rdfs: +PREFIX sh: +PREFIX xsd: + +INSERT DATA { + +ex:validPerson1 a ex:Person ; + ex:knows ex:peter. + +} diff --git a/shacl/src/test/resources/test-cases/class/targetNode/valid/case3/query1.rq b/shacl/src/test/resources/test-cases/class/targetNode/valid/case3/query1.rq new file mode 100644 index 000000000..891ac22cd --- /dev/null +++ b/shacl/src/test/resources/test-cases/class/targetNode/valid/case3/query1.rq @@ -0,0 +1,14 @@ +PREFIX ex: +PREFIX owl: +PREFIX rdf: +PREFIX rdfs: +PREFIX sh: +PREFIX xsd: + +INSERT DATA { + +ex:validPerson1 ex:knows ex:peter. + +ex:peter a ex:Person. + +} diff --git a/shacl/src/test/resources/test-cases/class/targetNode/valid/case3/query2.rq b/shacl/src/test/resources/test-cases/class/targetNode/valid/case3/query2.rq new file mode 100644 index 000000000..93fb72304 --- /dev/null +++ b/shacl/src/test/resources/test-cases/class/targetNode/valid/case3/query2.rq @@ -0,0 +1,12 @@ +PREFIX ex: +PREFIX owl: +PREFIX rdf: +PREFIX rdfs: +PREFIX sh: +PREFIX xsd: + +INSERT DATA { + +ex:validPerson1 a ex:Person . + +} diff --git a/shacl/src/test/resources/test-cases/class/targetNode/valid/case4/query1.rq b/shacl/src/test/resources/test-cases/class/targetNode/valid/case4/query1.rq new file mode 100644 index 000000000..4fe46ddbe --- /dev/null +++ b/shacl/src/test/resources/test-cases/class/targetNode/valid/case4/query1.rq @@ -0,0 +1,15 @@ +PREFIX ex: +PREFIX owl: +PREFIX rdf: +PREFIX rdfs: +PREFIX sh: +PREFIX xsd: + +INSERT DATA { + +ex:validPerson1 a ex:Person ; + ex:knows ex:peter. + +ex:peter a ex:Person. + +} diff --git a/shacl/src/test/resources/test-cases/class/targetNode/valid/case4/query2.rq b/shacl/src/test/resources/test-cases/class/targetNode/valid/case4/query2.rq new file mode 100644 index 000000000..2f9b7356d --- /dev/null +++ b/shacl/src/test/resources/test-cases/class/targetNode/valid/case4/query2.rq @@ -0,0 +1,15 @@ +PREFIX ex: +PREFIX owl: +PREFIX rdf: +PREFIX rdfs: +PREFIX sh: +PREFIX xsd: + +DELETE DATA { + +ex:peter a ex:Person. + +ex:validPerson1 ex:knows ex:peter. + + +} diff --git a/shacl/src/test/resources/test-cases/class/targetNode/valid/case5/query1.rq b/shacl/src/test/resources/test-cases/class/targetNode/valid/case5/query1.rq new file mode 100644 index 000000000..4fe46ddbe --- /dev/null +++ b/shacl/src/test/resources/test-cases/class/targetNode/valid/case5/query1.rq @@ -0,0 +1,15 @@ +PREFIX ex: +PREFIX owl: +PREFIX rdf: +PREFIX rdfs: +PREFIX sh: +PREFIX xsd: + +INSERT DATA { + +ex:validPerson1 a ex:Person ; + ex:knows ex:peter. + +ex:peter a ex:Person. + +} diff --git a/shacl/src/test/resources/test-cases/class/targetNode/valid/case5/query2.rq b/shacl/src/test/resources/test-cases/class/targetNode/valid/case5/query2.rq new file mode 100644 index 000000000..fe2951e94 --- /dev/null +++ b/shacl/src/test/resources/test-cases/class/targetNode/valid/case5/query2.rq @@ -0,0 +1,13 @@ +PREFIX ex: +PREFIX owl: +PREFIX rdf: +PREFIX rdfs: +PREFIX sh: +PREFIX xsd: + +DELETE DATA { + +ex:peter a ex:Person. + +ex:validPerson1 ex:knows ex:peter. +} diff --git a/shacl/src/test/resources/test-cases/class/targetNode/valid/case6/query1.rq b/shacl/src/test/resources/test-cases/class/targetNode/valid/case6/query1.rq new file mode 100644 index 000000000..4fac7590f --- /dev/null +++ b/shacl/src/test/resources/test-cases/class/targetNode/valid/case6/query1.rq @@ -0,0 +1,15 @@ +PREFIX ex: +PREFIX owl: +PREFIX rdf: +PREFIX rdfs: +PREFIX sh: +PREFIX xsd: + +INSERT DATA { + +[] a ex:Person ; + ex:knows _:b1. + +_:b1 a ex:Person. + +} diff --git a/shacl/src/test/resources/test-cases/class/targetNode/valid/case7/query1.rq b/shacl/src/test/resources/test-cases/class/targetNode/valid/case7/query1.rq new file mode 100644 index 000000000..be31a2745 --- /dev/null +++ b/shacl/src/test/resources/test-cases/class/targetNode/valid/case7/query1.rq @@ -0,0 +1,11 @@ +PREFIX ex: +PREFIX owl: +PREFIX rdf: +PREFIX rdfs: +PREFIX sh: +PREFIX xsd: + +INSERT DATA { + +ex:validPerson2 ex:knows "steve". +} diff --git a/shacl/src/test/resources/test-cases/class/targetNode/valid/case7/query2.rq b/shacl/src/test/resources/test-cases/class/targetNode/valid/case7/query2.rq new file mode 100644 index 000000000..4db24a1ef --- /dev/null +++ b/shacl/src/test/resources/test-cases/class/targetNode/valid/case7/query2.rq @@ -0,0 +1,18 @@ +PREFIX ex: +PREFIX owl: +PREFIX rdf: +PREFIX rdfs: +PREFIX sh: +PREFIX xsd: + +delete { + ex:validPerson2 ex:knows "steve". +} insert { + ex:validPerson1 a ex:Person ; + ex:knows ex:peter. + + ex:peter a ex:Person. + +} where { + ?a ?b ?c +} \ No newline at end of file diff --git a/shacl/src/test/resources/test-cases/datatype/targetNode/invalid/case1/query1.rq b/shacl/src/test/resources/test-cases/datatype/targetNode/invalid/case1/query1.rq new file mode 100644 index 000000000..b02e02cf6 --- /dev/null +++ b/shacl/src/test/resources/test-cases/datatype/targetNode/invalid/case1/query1.rq @@ -0,0 +1,13 @@ +PREFIX ex: +PREFIX owl: +PREFIX rdf: +PREFIX rdfs: +PREFIX sh: +PREFIX xsd: + +INSERT DATA { + +ex:validPerson1 a ex:Person ; + ex:age "123". + +} diff --git a/shacl/src/test/resources/test-cases/datatype/targetNode/invalid/case2/query1.rq b/shacl/src/test/resources/test-cases/datatype/targetNode/invalid/case2/query1.rq new file mode 100644 index 000000000..2db11fdda --- /dev/null +++ b/shacl/src/test/resources/test-cases/datatype/targetNode/invalid/case2/query1.rq @@ -0,0 +1,13 @@ +PREFIX ex: +PREFIX owl: +PREFIX rdf: +PREFIX rdfs: +PREFIX sh: +PREFIX xsd: + +INSERT DATA { + +ex:validPerson1 a ex:Person ; + ex:age 123. + +} diff --git a/shacl/src/test/resources/test-cases/datatype/targetNode/invalid/case2/query2.rq b/shacl/src/test/resources/test-cases/datatype/targetNode/invalid/case2/query2.rq new file mode 100644 index 000000000..3fdba605a --- /dev/null +++ b/shacl/src/test/resources/test-cases/datatype/targetNode/invalid/case2/query2.rq @@ -0,0 +1,12 @@ +PREFIX ex: +PREFIX owl: +PREFIX rdf: +PREFIX rdfs: +PREFIX sh: +PREFIX xsd: + +INSERT DATA { + +ex:validPerson1 ex:age "123". + +} diff --git a/shacl/src/test/resources/test-cases/datatype/targetNode/invalid/case3/query1.rq b/shacl/src/test/resources/test-cases/datatype/targetNode/invalid/case3/query1.rq new file mode 100644 index 000000000..3fdba605a --- /dev/null +++ b/shacl/src/test/resources/test-cases/datatype/targetNode/invalid/case3/query1.rq @@ -0,0 +1,12 @@ +PREFIX ex: +PREFIX owl: +PREFIX rdf: +PREFIX rdfs: +PREFIX sh: +PREFIX xsd: + +INSERT DATA { + +ex:validPerson1 ex:age "123". + +} diff --git a/shacl/src/test/resources/test-cases/datatype/targetNode/invalid/case3/query2.rq b/shacl/src/test/resources/test-cases/datatype/targetNode/invalid/case3/query2.rq new file mode 100644 index 000000000..93fb72304 --- /dev/null +++ b/shacl/src/test/resources/test-cases/datatype/targetNode/invalid/case3/query2.rq @@ -0,0 +1,12 @@ +PREFIX ex: +PREFIX owl: +PREFIX rdf: +PREFIX rdfs: +PREFIX sh: +PREFIX xsd: + +INSERT DATA { + +ex:validPerson1 a ex:Person . + +} diff --git a/shacl/src/test/resources/test-cases/datatype/targetNode/invalid/case4/query1.rq b/shacl/src/test/resources/test-cases/datatype/targetNode/invalid/case4/query1.rq new file mode 100644 index 000000000..3fdba605a --- /dev/null +++ b/shacl/src/test/resources/test-cases/datatype/targetNode/invalid/case4/query1.rq @@ -0,0 +1,12 @@ +PREFIX ex: +PREFIX owl: +PREFIX rdf: +PREFIX rdfs: +PREFIX sh: +PREFIX xsd: + +INSERT DATA { + +ex:validPerson1 ex:age "123". + +} diff --git a/shacl/src/test/resources/test-cases/datatype/targetNode/invalid/case4/query2.rq b/shacl/src/test/resources/test-cases/datatype/targetNode/invalid/case4/query2.rq new file mode 100644 index 000000000..f957a102c --- /dev/null +++ b/shacl/src/test/resources/test-cases/datatype/targetNode/invalid/case4/query2.rq @@ -0,0 +1,14 @@ +PREFIX ex: +PREFIX owl: +PREFIX rdf: +PREFIX rdfs: +PREFIX sh: +PREFIX xsd: + +INSERT DATA { + +ex:validPerson1 + ex:age 234 ; + a ex:Person . + +} diff --git a/shacl/src/test/resources/test-cases/datatype/targetNode/invalid/case5/query1.rq b/shacl/src/test/resources/test-cases/datatype/targetNode/invalid/case5/query1.rq new file mode 100644 index 000000000..3fdba605a --- /dev/null +++ b/shacl/src/test/resources/test-cases/datatype/targetNode/invalid/case5/query1.rq @@ -0,0 +1,12 @@ +PREFIX ex: +PREFIX owl: +PREFIX rdf: +PREFIX rdfs: +PREFIX sh: +PREFIX xsd: + +INSERT DATA { + +ex:validPerson1 ex:age "123". + +} diff --git a/shacl/src/test/resources/test-cases/datatype/targetNode/invalid/case5/query2.rq b/shacl/src/test/resources/test-cases/datatype/targetNode/invalid/case5/query2.rq new file mode 100644 index 000000000..e3d819e19 --- /dev/null +++ b/shacl/src/test/resources/test-cases/datatype/targetNode/invalid/case5/query2.rq @@ -0,0 +1,18 @@ +PREFIX ex: +PREFIX owl: +PREFIX rdf: +PREFIX rdfs: +PREFIX sh: +PREFIX xsd: + +INSERT DATA { + +ex:validPerson1 + ex:age 234 ; + a ex:Person . + +ex:validPerson2 + ex:age 234 ; + a ex:Person . + +} diff --git a/shacl/src/test/resources/test-cases/datatype/targetNode/shacl.ttl b/shacl/src/test/resources/test-cases/datatype/targetNode/shacl.ttl new file mode 100644 index 000000000..5461b3b39 --- /dev/null +++ b/shacl/src/test/resources/test-cases/datatype/targetNode/shacl.ttl @@ -0,0 +1,16 @@ +@base . +@prefix ex: . +@prefix owl: . +@prefix rdf: . +@prefix rdfs: . +@prefix sh: . +@prefix xsd: . + +ex:PersonShape + a sh:NodeShape ; + sh:targetNode ex:validPerson1, ex:validPerson2 ; + sh:property [ + sh:path ex:age ; + sh:datatype xsd:integer ; + ] . + diff --git a/shacl/src/test/resources/test-cases/datatype/targetNode/valid/case1/query1.rq b/shacl/src/test/resources/test-cases/datatype/targetNode/valid/case1/query1.rq new file mode 100644 index 000000000..2db11fdda --- /dev/null +++ b/shacl/src/test/resources/test-cases/datatype/targetNode/valid/case1/query1.rq @@ -0,0 +1,13 @@ +PREFIX ex: +PREFIX owl: +PREFIX rdf: +PREFIX rdfs: +PREFIX sh: +PREFIX xsd: + +INSERT DATA { + +ex:validPerson1 a ex:Person ; + ex:age 123. + +} diff --git a/shacl/src/test/resources/test-cases/datatype/targetNode/valid/case2/query1.rq b/shacl/src/test/resources/test-cases/datatype/targetNode/valid/case2/query1.rq new file mode 100644 index 000000000..2db11fdda --- /dev/null +++ b/shacl/src/test/resources/test-cases/datatype/targetNode/valid/case2/query1.rq @@ -0,0 +1,13 @@ +PREFIX ex: +PREFIX owl: +PREFIX rdf: +PREFIX rdfs: +PREFIX sh: +PREFIX xsd: + +INSERT DATA { + +ex:validPerson1 a ex:Person ; + ex:age 123. + +} diff --git a/shacl/src/test/resources/test-cases/datatype/targetNode/valid/case2/query2.rq b/shacl/src/test/resources/test-cases/datatype/targetNode/valid/case2/query2.rq new file mode 100644 index 000000000..2f2679c5f --- /dev/null +++ b/shacl/src/test/resources/test-cases/datatype/targetNode/valid/case2/query2.rq @@ -0,0 +1,13 @@ +PREFIX ex: +PREFIX owl: +PREFIX rdf: +PREFIX rdfs: +PREFIX sh: +PREFIX xsd: + +INSERT DATA { + +ex:validPerson1 ex:age 234. + +} + diff --git a/shacl/src/test/resources/test-cases/datatype/targetNode/valid/case3/query1.rq b/shacl/src/test/resources/test-cases/datatype/targetNode/valid/case3/query1.rq new file mode 100644 index 000000000..1777c8edd --- /dev/null +++ b/shacl/src/test/resources/test-cases/datatype/targetNode/valid/case3/query1.rq @@ -0,0 +1,12 @@ +PREFIX ex: +PREFIX owl: +PREFIX rdf: +PREFIX rdfs: +PREFIX sh: +PREFIX xsd: + +INSERT DATA { + +ex:validPerson3 ex:age "123". + +} diff --git a/shacl/src/test/resources/test-cases/datatype/targetNode/valid/case3/query2.rq b/shacl/src/test/resources/test-cases/datatype/targetNode/valid/case3/query2.rq new file mode 100644 index 000000000..d511402c8 --- /dev/null +++ b/shacl/src/test/resources/test-cases/datatype/targetNode/valid/case3/query2.rq @@ -0,0 +1,15 @@ +PREFIX ex: +PREFIX owl: +PREFIX rdf: +PREFIX rdfs: +PREFIX sh: +PREFIX xsd: + +INSERT DATA { + + +ex:validPerson2 + ex:age 234 ; + a ex:Person . + +} diff --git a/shacl/src/test/resources/test-cases/datatype/targetNode/valid/case4/query1.rq b/shacl/src/test/resources/test-cases/datatype/targetNode/valid/case4/query1.rq new file mode 100644 index 000000000..e645e4883 --- /dev/null +++ b/shacl/src/test/resources/test-cases/datatype/targetNode/valid/case4/query1.rq @@ -0,0 +1,14 @@ +PREFIX ex: +PREFIX owl: +PREFIX rdf: +PREFIX rdfs: +PREFIX sh: +PREFIX xsd: + +INSERT DATA { + + +ex:validPerson3 + ex:age "123". + +} diff --git a/shacl/src/test/resources/test-cases/datatype/targetNode/valid/case4/query2.rq b/shacl/src/test/resources/test-cases/datatype/targetNode/valid/case4/query2.rq new file mode 100644 index 000000000..648ce7fab --- /dev/null +++ b/shacl/src/test/resources/test-cases/datatype/targetNode/valid/case4/query2.rq @@ -0,0 +1,19 @@ +PREFIX ex: +PREFIX owl: +PREFIX rdf: +PREFIX rdfs: +PREFIX sh: +PREFIX xsd: + +delete { + ex:validPerson3 + ex:age "123". +} insert { + + ex:validPerson1 + ex:age 234 ; + a ex:Person . + +} where { + ?a ?b ?c. +} \ No newline at end of file diff --git a/shacl/src/test/resources/test-cases/datatype/targetNode/valid/case5/query1.rq b/shacl/src/test/resources/test-cases/datatype/targetNode/valid/case5/query1.rq new file mode 100644 index 000000000..8d94f24e9 --- /dev/null +++ b/shacl/src/test/resources/test-cases/datatype/targetNode/valid/case5/query1.rq @@ -0,0 +1,17 @@ +PREFIX ex: +PREFIX owl: +PREFIX rdf: +PREFIX rdfs: +PREFIX sh: +PREFIX xsd: + +INSERT DATA { + + +ex:validPerson3 + ex:age "123". + ex:validPerson1 + ex:age 234 ; + a ex:Person . + +} diff --git a/shacl/src/test/resources/test-cases/datatype/targetNode/valid/case5/query2.rq b/shacl/src/test/resources/test-cases/datatype/targetNode/valid/case5/query2.rq new file mode 100644 index 000000000..8ec8ae319 --- /dev/null +++ b/shacl/src/test/resources/test-cases/datatype/targetNode/valid/case5/query2.rq @@ -0,0 +1,16 @@ +PREFIX ex: +PREFIX owl: +PREFIX rdf: +PREFIX rdfs: +PREFIX sh: +PREFIX xsd: + +INSERT DATA { + + +ex:validPerson3 + ex:age "345". + ex:validPerson1 + ex:age 345 . + +} diff --git a/shacl/src/test/resources/test-cases/maxCount/targetNode/invalid/case1/query1.rq b/shacl/src/test/resources/test-cases/maxCount/targetNode/invalid/case1/query1.rq new file mode 100644 index 000000000..dff1e90e4 --- /dev/null +++ b/shacl/src/test/resources/test-cases/maxCount/targetNode/invalid/case1/query1.rq @@ -0,0 +1,13 @@ +PREFIX ex: +PREFIX owl: +PREFIX rdf: +PREFIX rdfs: +PREFIX sh: +PREFIX xsd: + +INSERT DATA { + +ex:validPerson1 a ex:Person ; + ex:ssn "123", "234", "567", "890". + +} diff --git a/shacl/src/test/resources/test-cases/maxCount/targetNode/invalid/case2/query1.rq b/shacl/src/test/resources/test-cases/maxCount/targetNode/invalid/case2/query1.rq new file mode 100644 index 000000000..abfcb0fd4 --- /dev/null +++ b/shacl/src/test/resources/test-cases/maxCount/targetNode/invalid/case2/query1.rq @@ -0,0 +1,12 @@ +PREFIX ex: +PREFIX owl: +PREFIX rdf: +PREFIX rdfs: +PREFIX sh: +PREFIX xsd: + +INSERT DATA { + +ex:validPerson1 ex:ssn "123", "234", "567", "890". + +} diff --git a/shacl/src/test/resources/test-cases/maxCount/targetNode/invalid/case2/query2.rq b/shacl/src/test/resources/test-cases/maxCount/targetNode/invalid/case2/query2.rq new file mode 100644 index 000000000..416b3ec78 --- /dev/null +++ b/shacl/src/test/resources/test-cases/maxCount/targetNode/invalid/case2/query2.rq @@ -0,0 +1,13 @@ +PREFIX ex: +PREFIX owl: +PREFIX rdf: +PREFIX rdfs: +PREFIX sh: +PREFIX xsd: + +INSERT DATA { + +ex:validPerson1 a ex:Person. + +} + diff --git a/shacl/src/test/resources/test-cases/maxCount/targetNode/invalid/case3/query1.rq b/shacl/src/test/resources/test-cases/maxCount/targetNode/invalid/case3/query1.rq new file mode 100644 index 000000000..b7c9c097b --- /dev/null +++ b/shacl/src/test/resources/test-cases/maxCount/targetNode/invalid/case3/query1.rq @@ -0,0 +1,12 @@ +PREFIX ex: +PREFIX owl: +PREFIX rdf: +PREFIX rdfs: +PREFIX sh: +PREFIX xsd: + +INSERT DATA { + +ex:validPerson1 ex:ssn "123", "234", "567". + +} diff --git a/shacl/src/test/resources/test-cases/maxCount/targetNode/invalid/case3/query2.rq b/shacl/src/test/resources/test-cases/maxCount/targetNode/invalid/case3/query2.rq new file mode 100644 index 000000000..416b3ec78 --- /dev/null +++ b/shacl/src/test/resources/test-cases/maxCount/targetNode/invalid/case3/query2.rq @@ -0,0 +1,13 @@ +PREFIX ex: +PREFIX owl: +PREFIX rdf: +PREFIX rdfs: +PREFIX sh: +PREFIX xsd: + +INSERT DATA { + +ex:validPerson1 a ex:Person. + +} + diff --git a/shacl/src/test/resources/test-cases/maxCount/targetNode/invalid/case3/query3.rq b/shacl/src/test/resources/test-cases/maxCount/targetNode/invalid/case3/query3.rq new file mode 100644 index 000000000..f268e310c --- /dev/null +++ b/shacl/src/test/resources/test-cases/maxCount/targetNode/invalid/case3/query3.rq @@ -0,0 +1,13 @@ +PREFIX ex: +PREFIX owl: +PREFIX rdf: +PREFIX rdfs: +PREFIX sh: +PREFIX xsd: + +INSERT DATA { + +ex:validPerson1 ex:ssn "123456789". + +} + diff --git a/shacl/src/test/resources/test-cases/maxCount/targetNode/shacl.ttl b/shacl/src/test/resources/test-cases/maxCount/targetNode/shacl.ttl new file mode 100644 index 000000000..25dbed6c8 --- /dev/null +++ b/shacl/src/test/resources/test-cases/maxCount/targetNode/shacl.ttl @@ -0,0 +1,16 @@ +@base . +@prefix ex: . +@prefix owl: . +@prefix rdf: . +@prefix rdfs: . +@prefix sh: . +@prefix xsd: . + +ex:PersonShape + a sh:NodeShape ; + sh:targetNode ex:validPerson1, ex:validPerson2 ; + sh:property [ + sh:path ex:ssn ; + sh:maxCount 3 + ] . + diff --git a/shacl/src/test/resources/test-cases/maxCount/targetNode/valid/case1/query1.rq b/shacl/src/test/resources/test-cases/maxCount/targetNode/valid/case1/query1.rq new file mode 100644 index 000000000..f0e0dd578 --- /dev/null +++ b/shacl/src/test/resources/test-cases/maxCount/targetNode/valid/case1/query1.rq @@ -0,0 +1,17 @@ +PREFIX ex: +PREFIX owl: +PREFIX rdf: +PREFIX rdfs: +PREFIX sh: +PREFIX xsd: + +INSERT DATA { + +ex:validPerson1 a ex:Person ; + ex:ssn "123", "456", "789". + +ex:validPerson2 ex:ssn "123". + +ex:validPerson3 ex:ssn 1 , 2 , 3 , 4 , 5. + +} \ No newline at end of file diff --git a/shacl/src/test/resources/test-cases/maxCount/targetNode/valid/case2/query1.rq b/shacl/src/test/resources/test-cases/maxCount/targetNode/valid/case2/query1.rq new file mode 100644 index 000000000..7354a2d08 --- /dev/null +++ b/shacl/src/test/resources/test-cases/maxCount/targetNode/valid/case2/query1.rq @@ -0,0 +1,14 @@ +PREFIX ex: +PREFIX owl: +PREFIX rdf: +PREFIX rdfs: +PREFIX sh: +PREFIX xsd: + +INSERT DATA { +ex:validPerson1 a ex:Person ; + ex:ssn "123", "456". + +ex:validPerson2 ex:ssn "123". + +} \ No newline at end of file diff --git a/shacl/src/test/resources/test-cases/maxCount/targetNode/valid/case2/query2.rq b/shacl/src/test/resources/test-cases/maxCount/targetNode/valid/case2/query2.rq new file mode 100644 index 000000000..d83a28ac6 --- /dev/null +++ b/shacl/src/test/resources/test-cases/maxCount/targetNode/valid/case2/query2.rq @@ -0,0 +1,11 @@ +PREFIX ex: +PREFIX owl: +PREFIX rdf: +PREFIX rdfs: +PREFIX sh: +PREFIX xsd: + +INSERT DATA { +ex:validPerson2 a ex:Person; + ex:ssn "456". +} diff --git a/shacl/src/test/resources/test-cases/maxCount/targetNode/valid/case3/query1.rq b/shacl/src/test/resources/test-cases/maxCount/targetNode/valid/case3/query1.rq new file mode 100644 index 000000000..7354a2d08 --- /dev/null +++ b/shacl/src/test/resources/test-cases/maxCount/targetNode/valid/case3/query1.rq @@ -0,0 +1,14 @@ +PREFIX ex: +PREFIX owl: +PREFIX rdf: +PREFIX rdfs: +PREFIX sh: +PREFIX xsd: + +INSERT DATA { +ex:validPerson1 a ex:Person ; + ex:ssn "123", "456". + +ex:validPerson2 ex:ssn "123". + +} \ No newline at end of file diff --git a/shacl/src/test/resources/test-cases/maxCount/targetNode/valid/case3/query2.rq b/shacl/src/test/resources/test-cases/maxCount/targetNode/valid/case3/query2.rq new file mode 100644 index 000000000..d83a28ac6 --- /dev/null +++ b/shacl/src/test/resources/test-cases/maxCount/targetNode/valid/case3/query2.rq @@ -0,0 +1,11 @@ +PREFIX ex: +PREFIX owl: +PREFIX rdf: +PREFIX rdfs: +PREFIX sh: +PREFIX xsd: + +INSERT DATA { +ex:validPerson2 a ex:Person; + ex:ssn "456". +} diff --git a/shacl/src/test/resources/test-cases/maxCount/targetNode/valid/case3/query3.rq b/shacl/src/test/resources/test-cases/maxCount/targetNode/valid/case3/query3.rq new file mode 100644 index 000000000..ca547863a --- /dev/null +++ b/shacl/src/test/resources/test-cases/maxCount/targetNode/valid/case3/query3.rq @@ -0,0 +1,14 @@ +PREFIX ex: +PREFIX owl: +PREFIX rdf: +PREFIX rdfs: +PREFIX sh: +PREFIX xsd: + +DELETE { +ex:validPerson2 a ex:Person. +} +INSERT{ +ex:validPerson2 ex:ssn "123456789". +} +WHERE{?a ?b ?c} \ No newline at end of file diff --git a/shacl/src/test/resources/test-cases/maxCount/targetNode/valid/case4/query1.rq b/shacl/src/test/resources/test-cases/maxCount/targetNode/valid/case4/query1.rq new file mode 100644 index 000000000..7c7dbea4f --- /dev/null +++ b/shacl/src/test/resources/test-cases/maxCount/targetNode/valid/case4/query1.rq @@ -0,0 +1,12 @@ +PREFIX ex: +PREFIX owl: +PREFIX rdf: +PREFIX rdfs: +PREFIX sh: +PREFIX xsd: + +INSERT DATA { + +ex:validPerson3 ex:ssn 1 , 2 , 3 , 4 . + +} \ No newline at end of file diff --git a/shacl/src/test/resources/test-cases/minCount/targetNode/invalid/case1/query1.rq b/shacl/src/test/resources/test-cases/minCount/targetNode/invalid/case1/query1.rq new file mode 100644 index 000000000..662f457f8 --- /dev/null +++ b/shacl/src/test/resources/test-cases/minCount/targetNode/invalid/case1/query1.rq @@ -0,0 +1,13 @@ +PREFIX ex: +PREFIX owl: +PREFIX rdf: +PREFIX rdfs: +PREFIX sh: +PREFIX xsd: + +INSERT DATA { + +ex:validPerson1 a ex:Person ; + ex:ssn "123". + +} diff --git a/shacl/src/test/resources/test-cases/minCount/targetNode/invalid/case2/query1.rq b/shacl/src/test/resources/test-cases/minCount/targetNode/invalid/case2/query1.rq new file mode 100644 index 000000000..7354a2d08 --- /dev/null +++ b/shacl/src/test/resources/test-cases/minCount/targetNode/invalid/case2/query1.rq @@ -0,0 +1,14 @@ +PREFIX ex: +PREFIX owl: +PREFIX rdf: +PREFIX rdfs: +PREFIX sh: +PREFIX xsd: + +INSERT DATA { +ex:validPerson1 a ex:Person ; + ex:ssn "123", "456". + +ex:validPerson2 ex:ssn "123". + +} \ No newline at end of file diff --git a/shacl/src/test/resources/test-cases/minCount/targetNode/invalid/case2/query2.rq b/shacl/src/test/resources/test-cases/minCount/targetNode/invalid/case2/query2.rq new file mode 100644 index 000000000..6194108fb --- /dev/null +++ b/shacl/src/test/resources/test-cases/minCount/targetNode/invalid/case2/query2.rq @@ -0,0 +1,10 @@ +PREFIX ex: +PREFIX owl: +PREFIX rdf: +PREFIX rdfs: +PREFIX sh: +PREFIX xsd: + +INSERT DATA { +ex:validPerson2 a ex:Person. +} diff --git a/shacl/src/test/resources/test-cases/minCount/targetNode/invalid/case3/query1.rq b/shacl/src/test/resources/test-cases/minCount/targetNode/invalid/case3/query1.rq new file mode 100644 index 000000000..4f6ec8cb0 --- /dev/null +++ b/shacl/src/test/resources/test-cases/minCount/targetNode/invalid/case3/query1.rq @@ -0,0 +1,12 @@ +PREFIX ex: +PREFIX owl: +PREFIX rdf: +PREFIX rdfs: +PREFIX sh: +PREFIX xsd: + +INSERT DATA { +ex:validPerson1 a ex:Person ; + ex:ssn "123", "456". + +} \ No newline at end of file diff --git a/shacl/src/test/resources/test-cases/minCount/targetNode/invalid/case3/query2.rq b/shacl/src/test/resources/test-cases/minCount/targetNode/invalid/case3/query2.rq new file mode 100644 index 000000000..b66cba355 --- /dev/null +++ b/shacl/src/test/resources/test-cases/minCount/targetNode/invalid/case3/query2.rq @@ -0,0 +1,11 @@ +PREFIX ex: +PREFIX owl: +PREFIX rdf: +PREFIX rdfs: +PREFIX sh: +PREFIX xsd: + +DELETE DATA { +ex:validPerson1 ex:ssn "123". + +} \ No newline at end of file diff --git a/shacl/src/test/resources/test-cases/minCount/targetNode/shacl.ttl b/shacl/src/test/resources/test-cases/minCount/targetNode/shacl.ttl new file mode 100644 index 000000000..2119c41c8 --- /dev/null +++ b/shacl/src/test/resources/test-cases/minCount/targetNode/shacl.ttl @@ -0,0 +1,17 @@ +@base . +@prefix ex: . +@prefix owl: . +@prefix rdf: . +@prefix rdfs: . +@prefix sh: . +@prefix xsd: . + +ex:PersonShape + a sh:NodeShape ; + sh:targetNode ex:validPerson1, ex:validPerson2 ; + sh:property [ + sh:path ex:ssn ; + sh:minCount 2 ; + + ] . + diff --git a/shacl/src/test/resources/test-cases/minCount/targetNode/valid/case1/query1.rq b/shacl/src/test/resources/test-cases/minCount/targetNode/valid/case1/query1.rq new file mode 100644 index 000000000..b5a5ffa16 --- /dev/null +++ b/shacl/src/test/resources/test-cases/minCount/targetNode/valid/case1/query1.rq @@ -0,0 +1,15 @@ +PREFIX ex: +PREFIX owl: +PREFIX rdf: +PREFIX rdfs: +PREFIX sh: +PREFIX xsd: + +INSERT DATA { + +ex:validPerson1 a ex:Person ; + ex:ssn "123", "456". + +ex:validPerson3 ex:ssn "123". + +} \ No newline at end of file diff --git a/shacl/src/test/resources/test-cases/minCount/targetNode/valid/case2/query1.rq b/shacl/src/test/resources/test-cases/minCount/targetNode/valid/case2/query1.rq new file mode 100644 index 000000000..0819334ee --- /dev/null +++ b/shacl/src/test/resources/test-cases/minCount/targetNode/valid/case2/query1.rq @@ -0,0 +1,13 @@ +PREFIX ex: +PREFIX owl: +PREFIX rdf: +PREFIX rdfs: +PREFIX sh: +PREFIX xsd: + +INSERT DATA { +ex:validPerson1 a ex:Person ; + ex:ssn "123", "456". + + +} \ No newline at end of file diff --git a/shacl/src/test/resources/test-cases/minCount/targetNode/valid/case2/query2.rq b/shacl/src/test/resources/test-cases/minCount/targetNode/valid/case2/query2.rq new file mode 100644 index 000000000..a1d90f55c --- /dev/null +++ b/shacl/src/test/resources/test-cases/minCount/targetNode/valid/case2/query2.rq @@ -0,0 +1,12 @@ +PREFIX ex: +PREFIX owl: +PREFIX rdf: +PREFIX rdfs: +PREFIX sh: +PREFIX xsd: + +INSERT DATA { +ex:validPerson2 ex:ssn "123". + +ex:validPerson2 ex:ssn "456". +} diff --git a/shacl/src/test/resources/test-cases/minCount/targetNode/valid/case3/query1.rq b/shacl/src/test/resources/test-cases/minCount/targetNode/valid/case3/query1.rq new file mode 100644 index 000000000..85bca204c --- /dev/null +++ b/shacl/src/test/resources/test-cases/minCount/targetNode/valid/case3/query1.rq @@ -0,0 +1,11 @@ +PREFIX ex: +PREFIX owl: +PREFIX rdf: +PREFIX rdfs: +PREFIX sh: +PREFIX xsd: + +INSERT DATA { +ex:validPerson1 ex:ssn "123", "456", "789". + +} \ No newline at end of file diff --git a/shacl/src/test/resources/test-cases/minCount/targetNode/valid/case3/query2.rq b/shacl/src/test/resources/test-cases/minCount/targetNode/valid/case3/query2.rq new file mode 100644 index 000000000..b8733702c --- /dev/null +++ b/shacl/src/test/resources/test-cases/minCount/targetNode/valid/case3/query2.rq @@ -0,0 +1,10 @@ +PREFIX ex: +PREFIX owl: +PREFIX rdf: +PREFIX rdfs: +PREFIX sh: +PREFIX xsd: + +DELETE DATA { + ex:validPerson1 ex:ssn "123" . +} \ No newline at end of file diff --git a/shacl/src/test/resources/test-cases/minCount/targetNode/valid/case4/query1.rq b/shacl/src/test/resources/test-cases/minCount/targetNode/valid/case4/query1.rq new file mode 100644 index 000000000..7b787566d --- /dev/null +++ b/shacl/src/test/resources/test-cases/minCount/targetNode/valid/case4/query1.rq @@ -0,0 +1,12 @@ +PREFIX ex: +PREFIX owl: +PREFIX rdf: +PREFIX rdfs: +PREFIX sh: +PREFIX xsd: + +INSERT DATA { +ex:validPerson1 a ex:Person ; + ex:ssn "123", "456", "789". + +} \ No newline at end of file diff --git a/shacl/src/test/resources/test-cases/minCount/targetNode/valid/case4/query2.rq b/shacl/src/test/resources/test-cases/minCount/targetNode/valid/case4/query2.rq new file mode 100644 index 000000000..9e6f58cca --- /dev/null +++ b/shacl/src/test/resources/test-cases/minCount/targetNode/valid/case4/query2.rq @@ -0,0 +1,11 @@ +PREFIX ex: +PREFIX owl: +PREFIX rdf: +PREFIX rdfs: +PREFIX sh: +PREFIX xsd: + +DELETE DATA { +ex:validPerson1 a ex:Person . + +} \ No newline at end of file diff --git a/shacl/src/test/resources/test-cases/minCount/targetNode/valid/case4/query3.rq b/shacl/src/test/resources/test-cases/minCount/targetNode/valid/case4/query3.rq new file mode 100644 index 000000000..720333564 --- /dev/null +++ b/shacl/src/test/resources/test-cases/minCount/targetNode/valid/case4/query3.rq @@ -0,0 +1,11 @@ +PREFIX ex: +PREFIX owl: +PREFIX rdf: +PREFIX rdfs: +PREFIX sh: +PREFIX xsd: + +DELETE DATA { +ex:validPerson1 ex:ssn "123" . + +} \ No newline at end of file diff --git a/shacl/src/test/resources/test-cases/minCount/targetNode/valid/case5/query1.rq b/shacl/src/test/resources/test-cases/minCount/targetNode/valid/case5/query1.rq new file mode 100644 index 000000000..a7c361d97 --- /dev/null +++ b/shacl/src/test/resources/test-cases/minCount/targetNode/valid/case5/query1.rq @@ -0,0 +1,12 @@ +PREFIX ex: +PREFIX owl: +PREFIX rdf: +PREFIX rdfs: +PREFIX sh: +PREFIX xsd: + +INSERT DATA { + +[] ex:ssn "123". + +} \ No newline at end of file diff --git a/shacl/src/test/resources/test-cases/minCount/targetNode/valid/case5/query2.rq b/shacl/src/test/resources/test-cases/minCount/targetNode/valid/case5/query2.rq new file mode 100644 index 000000000..10551edc9 --- /dev/null +++ b/shacl/src/test/resources/test-cases/minCount/targetNode/valid/case5/query2.rq @@ -0,0 +1,13 @@ +PREFIX ex: +PREFIX owl: +PREFIX rdf: +PREFIX rdfs: +PREFIX sh: +PREFIX xsd: + +insert { + ?a a ex:Person; + ex:ssn "456". +} where{ + ?a ex:ssn ?b. +} \ No newline at end of file diff --git a/shacl/src/test/resources/test-cases/or/datatypeTargetNode/invalid/case1/query1.rq b/shacl/src/test/resources/test-cases/or/datatypeTargetNode/invalid/case1/query1.rq new file mode 100644 index 000000000..ab1797b67 --- /dev/null +++ b/shacl/src/test/resources/test-cases/or/datatypeTargetNode/invalid/case1/query1.rq @@ -0,0 +1,13 @@ +PREFIX ex: +PREFIX owl: +PREFIX rdf: +PREFIX rdfs: +PREFIX sh: +PREFIX xsd: + +INSERT DATA { + +ex:validPerson1 a ex:Person ; + ex:age "abc". + +} diff --git a/shacl/src/test/resources/test-cases/or/datatypeTargetNode/shacl.ttl b/shacl/src/test/resources/test-cases/or/datatypeTargetNode/shacl.ttl new file mode 100644 index 000000000..0fd50c09e --- /dev/null +++ b/shacl/src/test/resources/test-cases/or/datatypeTargetNode/shacl.ttl @@ -0,0 +1,27 @@ +@base . +@prefix ex: . +@prefix owl: . +@prefix rdf: . +@prefix rdfs: . +@prefix sh: . +@prefix xsd: . + +ex:PersonShape + a sh:NodeShape ; + sh:targetNode ex:validPerson1 ; + sh:property ex:personShapeOr. + + +ex:personShapeOr + sh:or ( + ex:personShapeAgeInteger + ex:personShapeAgeLong + ) . + +ex:personShapeAgeInteger + sh:path ex:age ; + sh:datatype xsd:integer . + +ex:personShapeAgeLong + sh:path ex:age ; + sh:datatype xsd:long . \ No newline at end of file diff --git a/shacl/src/test/resources/test-cases/or/datatypeTargetNode/valid/case1/query1.rq b/shacl/src/test/resources/test-cases/or/datatypeTargetNode/valid/case1/query1.rq new file mode 100644 index 000000000..f0e8277ce --- /dev/null +++ b/shacl/src/test/resources/test-cases/or/datatypeTargetNode/valid/case1/query1.rq @@ -0,0 +1,13 @@ +PREFIX ex: +PREFIX owl: +PREFIX rdf: +PREFIX rdfs: +PREFIX sh: +PREFIX xsd: + +INSERT DATA { + +ex:validPerson1 a ex:Person ; + ex:age 123, "234"^^xsd:long. + +}