Skip to content

Commit 901570a

Browse files
committed
GH-4770 support adding and removing by path
1 parent eb9d21c commit 901570a

41 files changed

Lines changed: 820 additions & 461 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

core/sail/shacl/src/main/java/org/eclipse/rdf4j/sail/shacl/ast/constraintcomponents/AbstractConstraintComponent.java

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,9 +22,16 @@
2222
import org.eclipse.rdf4j.sail.shacl.ast.StatementMatcher.Variable;
2323
import org.eclipse.rdf4j.sail.shacl.ast.ValidationApproach;
2424
import org.eclipse.rdf4j.sail.shacl.ast.ValidationQuery;
25+
import org.eclipse.rdf4j.sail.shacl.ast.paths.Path;
26+
import org.eclipse.rdf4j.sail.shacl.ast.planNodes.BufferedSplitter;
2527
import org.eclipse.rdf4j.sail.shacl.ast.planNodes.EmptyNode;
2628
import org.eclipse.rdf4j.sail.shacl.ast.planNodes.PlanNode;
2729
import org.eclipse.rdf4j.sail.shacl.ast.planNodes.PlanNodeProvider;
30+
import org.eclipse.rdf4j.sail.shacl.ast.planNodes.ReduceTargets;
31+
import org.eclipse.rdf4j.sail.shacl.ast.planNodes.TrimToTarget;
32+
import org.eclipse.rdf4j.sail.shacl.ast.planNodes.UnionNode;
33+
import org.eclipse.rdf4j.sail.shacl.ast.planNodes.Unique;
34+
import org.eclipse.rdf4j.sail.shacl.ast.targets.EffectiveTarget;
2835
import org.eclipse.rdf4j.sail.shacl.ast.targets.TargetChain;
2936
import org.eclipse.rdf4j.sail.shacl.wrapper.data.ConnectionsGroup;
3037
import org.eclipse.rdf4j.sail.shacl.wrapper.data.RdfsSubClassOfReasoner;
@@ -144,4 +151,27 @@ public String stringRepresentationOfValue(Value value) {
144151
throw new IllegalStateException(value.getClass().getSimpleName());
145152
}
146153

154+
static PlanNode getAllTargetsIncludingThoseAddedByPath(ConnectionsGroup connectionsGroup,
155+
ValidationSettings validationSettings, Scope scope, EffectiveTarget effectiveTarget, Path path,
156+
boolean includeTargetsAffectedByRemoval) {
157+
PlanNode allTargets;
158+
BufferedSplitter addedTargets = new BufferedSplitter(
159+
effectiveTarget.getPlanNode(connectionsGroup, validationSettings.getDataGraph(),
160+
scope, includeTargetsAffectedByRemoval, null));
161+
162+
PlanNode addedByPath = path.getAllAdded(connectionsGroup, validationSettings.getDataGraph(), null);
163+
164+
addedByPath = Unique.getInstance(new TrimToTarget(addedByPath), false);
165+
166+
addedByPath = new ReduceTargets(addedByPath, addedTargets.getPlanNode());
167+
168+
addedByPath = effectiveTarget.extend(addedByPath, connectionsGroup, validationSettings.getDataGraph(),
169+
scope, EffectiveTarget.Extend.left,
170+
false,
171+
null);
172+
173+
allTargets = UnionNode.getInstance(addedTargets.getPlanNode(), addedByPath);
174+
return allTargets;
175+
}
176+
147177
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,232 @@
1+
/*******************************************************************************
2+
* Copyright (c) 2020 Eclipse RDF4J contributors.
3+
*
4+
* All rights reserved. This program and the accompanying materials
5+
* are made available under the terms of the Eclipse Distribution License v1.0
6+
* which accompanies this distribution, and is available at
7+
* http://www.eclipse.org/org/documents/edl-v10.php.
8+
*
9+
* SPDX-License-Identifier: BSD-3-Clause
10+
*******************************************************************************/
11+
12+
package org.eclipse.rdf4j.sail.shacl.ast.constraintcomponents;
13+
14+
import java.util.List;
15+
import java.util.Optional;
16+
import java.util.Set;
17+
18+
import org.eclipse.rdf4j.model.IRI;
19+
import org.eclipse.rdf4j.model.Literal;
20+
import org.eclipse.rdf4j.model.Model;
21+
import org.eclipse.rdf4j.model.Resource;
22+
import org.eclipse.rdf4j.model.Value;
23+
import org.eclipse.rdf4j.sail.shacl.ValidationSettings;
24+
import org.eclipse.rdf4j.sail.shacl.ast.SparqlFragment;
25+
import org.eclipse.rdf4j.sail.shacl.ast.StatementMatcher;
26+
import org.eclipse.rdf4j.sail.shacl.ast.ValidationApproach;
27+
import org.eclipse.rdf4j.sail.shacl.ast.paths.Path;
28+
import org.eclipse.rdf4j.sail.shacl.ast.planNodes.PlanNode;
29+
import org.eclipse.rdf4j.sail.shacl.ast.planNodes.PlanNodeProvider;
30+
import org.eclipse.rdf4j.sail.shacl.ast.planNodes.ShiftToPropertyShape;
31+
import org.eclipse.rdf4j.sail.shacl.ast.planNodes.TrimToTarget;
32+
import org.eclipse.rdf4j.sail.shacl.ast.planNodes.UnionNode;
33+
import org.eclipse.rdf4j.sail.shacl.ast.planNodes.Unique;
34+
import org.eclipse.rdf4j.sail.shacl.ast.planNodes.UnorderedSelect;
35+
import org.eclipse.rdf4j.sail.shacl.ast.planNodes.ValidationTuple;
36+
import org.eclipse.rdf4j.sail.shacl.ast.targets.EffectiveTarget;
37+
import org.eclipse.rdf4j.sail.shacl.ast.targets.TargetChain;
38+
import org.eclipse.rdf4j.sail.shacl.wrapper.data.ConnectionsGroup;
39+
40+
abstract class AbstractPairwiseConstraintComponent extends AbstractConstraintComponent {
41+
42+
IRI predicate;
43+
44+
public AbstractPairwiseConstraintComponent(IRI predicate) {
45+
this.predicate = predicate;
46+
}
47+
48+
abstract IRI getIRI();
49+
50+
@Override
51+
public void toModel(Resource subject, IRI predicate, Model model, Set<Resource> cycleDetection) {
52+
model.add(subject, getIRI(), this.predicate);
53+
}
54+
55+
@Override
56+
public PlanNode generateTransactionalValidationPlan(ConnectionsGroup connectionsGroup,
57+
ValidationSettings validationSettings, PlanNodeProvider overrideTargetNode, Scope scope) {
58+
59+
StatementMatcher.StableRandomVariableProvider stableRandomVariableProvider = new StatementMatcher.StableRandomVariableProvider();
60+
61+
TargetChain targetChain = getTargetChain();
62+
63+
EffectiveTarget effectiveTarget = targetChain.getEffectiveTarget(scope,
64+
connectionsGroup.getRdfsSubClassOfReasoner(), stableRandomVariableProvider);
65+
66+
Optional<Path> path = targetChain.getPath();
67+
68+
PlanNode allTargets;
69+
70+
if (overrideTargetNode != null) {
71+
allTargets = effectiveTarget.extend(overrideTargetNode.getPlanNode(), connectionsGroup,
72+
validationSettings.getDataGraph(), scope, EffectiveTarget.Extend.right, false, null);
73+
} else {
74+
if (scope == Scope.propertyShape) {
75+
allTargets = getAllTargetsIncludingThoseAddedByPath(connectionsGroup, validationSettings, scope,
76+
effectiveTarget, path.get(), true);
77+
78+
PlanNode allTargetsBasedOnPredicate = getAllTargetsBasedOnPredicate(connectionsGroup,
79+
validationSettings,
80+
effectiveTarget);
81+
82+
allTargets = Unique.getInstance(UnionNode.getInstance(allTargets, allTargetsBasedOnPredicate), false);
83+
84+
} else {
85+
allTargets = effectiveTarget.getPlanNode(connectionsGroup, validationSettings.getDataGraph(), scope,
86+
false, null);
87+
88+
PlanNode allTargetsBasedOnPredicate = getAllTargetsBasedOnPredicate(connectionsGroup,
89+
validationSettings,
90+
effectiveTarget);
91+
92+
allTargets = Unique.getInstance(UnionNode.getInstance(allTargets, allTargetsBasedOnPredicate), false);
93+
}
94+
95+
}
96+
97+
StatementMatcher.Variable<Resource> subject = new StatementMatcher.Variable<>("a");
98+
StatementMatcher.Variable<Value> object = new StatementMatcher.Variable<>("c");
99+
100+
SparqlFragment targetQueryFragment = null;
101+
102+
if (path.isPresent()) {
103+
targetQueryFragment = path.get()
104+
.getTargetQueryFragment(subject, object, connectionsGroup.getRdfsSubClassOfReasoner(),
105+
stableRandomVariableProvider, Set.of());
106+
}
107+
108+
return getPairwiseCheck(connectionsGroup, validationSettings, allTargets, subject, object, targetQueryFragment);
109+
}
110+
111+
abstract PlanNode getPairwiseCheck(ConnectionsGroup connectionsGroup, ValidationSettings validationSettings,
112+
PlanNode allTargets, StatementMatcher.Variable<Resource> subject, StatementMatcher.Variable<Value> object,
113+
SparqlFragment targetQueryFragment);
114+
115+
private PlanNode getAllTargetsBasedOnPredicate(ConnectionsGroup connectionsGroup,
116+
ValidationSettings validationSettings, EffectiveTarget effectiveTarget) {
117+
PlanNode addedByPredicate = new UnorderedSelect(connectionsGroup.getAddedStatements(), null, predicate, null,
118+
validationSettings.getDataGraph(), (s, d) -> {
119+
return new ValidationTuple(s.getSubject(), Scope.propertyShape, false, d);
120+
});
121+
122+
PlanNode removedByPredicate = new UnorderedSelect(connectionsGroup.getRemovedStatements(), null, predicate,
123+
null, validationSettings.getDataGraph(), (s, d) -> {
124+
return new ValidationTuple(s.getSubject(), Scope.propertyShape, false, d);
125+
});
126+
127+
PlanNode targetFilter1 = effectiveTarget.getTargetFilter(connectionsGroup, validationSettings.getDataGraph(),
128+
addedByPredicate);
129+
PlanNode targetFilter2 = effectiveTarget.getTargetFilter(connectionsGroup, validationSettings.getDataGraph(),
130+
removedByPredicate);
131+
132+
return Unique.getInstance(UnionNode.getInstance(targetFilter1, targetFilter2), false);
133+
}
134+
135+
@Override
136+
public PlanNode getAllTargetsPlan(ConnectionsGroup connectionsGroup, Resource[] dataGraph, Scope scope,
137+
StatementMatcher.StableRandomVariableProvider stableRandomVariableProvider) {
138+
assert scope == Scope.propertyShape;
139+
140+
PlanNode allTargetsPlan = getTargetChain()
141+
.getEffectiveTarget(Scope.nodeShape, connectionsGroup.getRdfsSubClassOfReasoner(),
142+
stableRandomVariableProvider)
143+
.getPlanNode(connectionsGroup, dataGraph, Scope.nodeShape, true, null);
144+
145+
allTargetsPlan = new ShiftToPropertyShape(allTargetsPlan);
146+
147+
// removed statements that match predicate could affect sh:or
148+
if (connectionsGroup.getStats().hasRemoved()) {
149+
PlanNode deletedTypes = new UnorderedSelect(connectionsGroup.getRemovedStatements(), null, predicate,
150+
null, dataGraph, UnorderedSelect.Mapper.SubjectScopedMapper.getFunction(Scope.propertyShape));
151+
deletedTypes = getTargetChain()
152+
.getEffectiveTarget(Scope.propertyShape, connectionsGroup.getRdfsSubClassOfReasoner(),
153+
stableRandomVariableProvider)
154+
.getTargetFilter(connectionsGroup, dataGraph, deletedTypes);
155+
deletedTypes = getTargetChain()
156+
.getEffectiveTarget(Scope.propertyShape, connectionsGroup.getRdfsSubClassOfReasoner(),
157+
stableRandomVariableProvider)
158+
.extend(deletedTypes, connectionsGroup, dataGraph, Scope.propertyShape, EffectiveTarget.Extend.left,
159+
false,
160+
null);
161+
allTargetsPlan = UnionNode.getInstanceDedupe(allTargetsPlan, deletedTypes);
162+
}
163+
164+
// added statements that match predicate could affect sh:not
165+
if (connectionsGroup.getStats().hasAdded()) {
166+
PlanNode addedTypes = new UnorderedSelect(connectionsGroup.getAddedStatements(), null, predicate,
167+
null, dataGraph, UnorderedSelect.Mapper.SubjectScopedMapper.getFunction(Scope.propertyShape));
168+
addedTypes = getTargetChain()
169+
.getEffectiveTarget(Scope.propertyShape, connectionsGroup.getRdfsSubClassOfReasoner(),
170+
stableRandomVariableProvider)
171+
.getTargetFilter(connectionsGroup, dataGraph, addedTypes);
172+
addedTypes = getTargetChain()
173+
.getEffectiveTarget(Scope.propertyShape, connectionsGroup.getRdfsSubClassOfReasoner(),
174+
stableRandomVariableProvider)
175+
.extend(addedTypes, connectionsGroup, dataGraph, Scope.propertyShape, EffectiveTarget.Extend.left,
176+
false,
177+
null);
178+
allTargetsPlan = UnionNode.getInstanceDedupe(allTargetsPlan, addedTypes);
179+
}
180+
181+
return Unique.getInstance(new TrimToTarget(allTargetsPlan), false);
182+
}
183+
184+
@Override
185+
public ValidationApproach getPreferredValidationApproach(ConnectionsGroup connectionsGroup) {
186+
return ValidationApproach.Transactional;
187+
}
188+
189+
@Override
190+
public ValidationApproach getOptimalBulkValidationApproach() {
191+
return ValidationApproach.Transactional;
192+
}
193+
194+
@Override
195+
public boolean requiresEvaluation(ConnectionsGroup connectionsGroup, Scope scope, Resource[] dataGraph,
196+
StatementMatcher.StableRandomVariableProvider stableRandomVariableProvider) {
197+
198+
// todo both consider the target chain with added and removed values (path), and also added and removed values
199+
// for the predicate path
200+
201+
return true;
202+
}
203+
204+
@Override
205+
public ConstraintComponent deepClone() {
206+
throw new UnsupportedOperationException();
207+
}
208+
209+
@Override
210+
public List<Literal> getDefaultMessage() {
211+
return List.of();
212+
}
213+
214+
@Override
215+
public boolean equals(Object o) {
216+
if (this == o) {
217+
return true;
218+
}
219+
if (o == null || getClass() != o.getClass()) {
220+
return false;
221+
}
222+
223+
AbstractPairwiseConstraintComponent that = (AbstractPairwiseConstraintComponent) o;
224+
225+
return predicate.equals(that.predicate);
226+
}
227+
228+
@Override
229+
public int hashCode() {
230+
return predicate.hashCode() + "LessThanConstraintComponent".hashCode();
231+
}
232+
}

core/sail/shacl/src/main/java/org/eclipse/rdf4j/sail/shacl/ast/constraintcomponents/ClassConstraintComponent.java

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,7 @@ public PlanNode generateTransactionalValidationPlan(ConnectionsGroup connections
7676
PlanNodeProvider overrideTargetNode, Scope scope) {
7777
StatementMatcher.StableRandomVariableProvider stableRandomVariableProvider = new StatementMatcher.StableRandomVariableProvider();
7878

79-
EffectiveTarget target = getTargetChain().getEffectiveTarget(scope,
79+
EffectiveTarget effectiveTarget = getTargetChain().getEffectiveTarget(scope,
8080
connectionsGroup.getRdfsSubClassOfReasoner(), stableRandomVariableProvider);
8181

8282
if (scope == Scope.propertyShape) {
@@ -85,23 +85,25 @@ public PlanNode generateTransactionalValidationPlan(ConnectionsGroup connections
8585
PlanNode addedTargets;
8686

8787
if (overrideTargetNode != null) {
88-
addedTargets = target.extend(overrideTargetNode.getPlanNode(), connectionsGroup,
88+
addedTargets = effectiveTarget.extend(overrideTargetNode.getPlanNode(), connectionsGroup,
8989
validationSettings.getDataGraph(), scope,
9090
EffectiveTarget.Extend.right,
9191
false, null);
9292

9393
} else {
9494
BufferedSplitter addedTargetsBufferedSplitter = new BufferedSplitter(
95-
target.getPlanNode(connectionsGroup, validationSettings.getDataGraph(), scope, false, null));
95+
effectiveTarget.getPlanNode(connectionsGroup, validationSettings.getDataGraph(), scope, false,
96+
null));
9697
addedTargets = addedTargetsBufferedSplitter.getPlanNode();
9798
PlanNode addedByPath = path.getAllAdded(connectionsGroup, validationSettings.getDataGraph(), null);
9899

99-
addedByPath = target.getTargetFilter(connectionsGroup,
100+
addedByPath = effectiveTarget.getTargetFilter(connectionsGroup,
100101
validationSettings.getDataGraph(), Unique.getInstance(new TrimToTarget(addedByPath), false));
101102

102103
addedByPath = new ReduceTargets(addedByPath, addedTargetsBufferedSplitter.getPlanNode());
103104

104-
addedByPath = target.extend(addedByPath, connectionsGroup, validationSettings.getDataGraph(), scope,
105+
addedByPath = effectiveTarget.extend(addedByPath, connectionsGroup, validationSettings.getDataGraph(),
106+
scope,
105107
EffectiveTarget.Extend.left, false,
106108
null);
107109

@@ -162,12 +164,13 @@ public PlanNode generateTransactionalValidationPlan(ConnectionsGroup connections
162164
PlanNode addedTargets;
163165

164166
if (overrideTargetNode != null) {
165-
addedTargets = target.extend(overrideTargetNode.getPlanNode(), connectionsGroup,
167+
addedTargets = effectiveTarget.extend(overrideTargetNode.getPlanNode(), connectionsGroup,
166168
validationSettings.getDataGraph(), scope,
167169
EffectiveTarget.Extend.right,
168170
false, null);
169171
} else {
170-
addedTargets = target.getPlanNode(connectionsGroup, validationSettings.getDataGraph(), scope, false,
172+
addedTargets = effectiveTarget.getPlanNode(connectionsGroup, validationSettings.getDataGraph(), scope,
173+
false,
171174
null);
172175

173176
if (connectionsGroup.getStats().hasRemoved()) {

core/sail/shacl/src/main/java/org/eclipse/rdf4j/sail/shacl/ast/constraintcomponents/DashHasValueInConstraintComponent.java

Lines changed: 7 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,6 @@
3939
import org.eclipse.rdf4j.sail.shacl.ast.planNodes.ShiftToPropertyShape;
4040
import org.eclipse.rdf4j.sail.shacl.ast.planNodes.TrimToTarget;
4141
import org.eclipse.rdf4j.sail.shacl.ast.planNodes.UnBufferedPlanNode;
42-
import org.eclipse.rdf4j.sail.shacl.ast.planNodes.UnionNode;
4342
import org.eclipse.rdf4j.sail.shacl.ast.planNodes.Unique;
4443
import org.eclipse.rdf4j.sail.shacl.ast.planNodes.ValidationTuple;
4544
import org.eclipse.rdf4j.sail.shacl.ast.planNodes.ValueInFilter;
@@ -88,7 +87,7 @@ public PlanNode generateTransactionalValidationPlan(ConnectionsGroup connections
8887
PlanNodeProvider overrideTargetNode, Scope scope) {
8988
StatementMatcher.StableRandomVariableProvider stableRandomVariableProvider = new StatementMatcher.StableRandomVariableProvider();
9089

91-
EffectiveTarget target = getTargetChain().getEffectiveTarget(scope,
90+
EffectiveTarget effectiveTarget = getTargetChain().getEffectiveTarget(scope,
9291
connectionsGroup.getRdfsSubClassOfReasoner(), stableRandomVariableProvider);
9392

9493
if (scope == Scope.propertyShape) {
@@ -97,23 +96,13 @@ public PlanNode generateTransactionalValidationPlan(ConnectionsGroup connections
9796
PlanNode addedTargets;
9897

9998
if (overrideTargetNode != null) {
100-
addedTargets = target.extend(overrideTargetNode.getPlanNode(), connectionsGroup,
99+
addedTargets = effectiveTarget.extend(overrideTargetNode.getPlanNode(), connectionsGroup,
101100
validationSettings.getDataGraph(), scope,
102101
EffectiveTarget.Extend.right,
103102
false, null);
104103
} else {
105-
addedTargets = target.getPlanNode(connectionsGroup, validationSettings.getDataGraph(), scope, true,
106-
null);
107-
PlanNode addedByPath = path.getAllAdded(connectionsGroup, validationSettings.getDataGraph(), null);
108-
109-
addedByPath = target.getTargetFilter(connectionsGroup,
110-
validationSettings.getDataGraph(), Unique.getInstance(new TrimToTarget(addedByPath), false));
111-
addedByPath = target.extend(addedByPath, connectionsGroup, validationSettings.getDataGraph(), scope,
112-
EffectiveTarget.Extend.left, false,
113-
null);
114-
115-
addedTargets = UnionNode.getInstance(addedByPath, addedTargets);
116-
addedTargets = Unique.getInstance(addedTargets, false);
104+
addedTargets = getAllTargetsIncludingThoseAddedByPath(connectionsGroup, validationSettings, scope,
105+
effectiveTarget, path, true);
117106
}
118107

119108
PlanNode joined = new BulkedExternalLeftOuterJoin(
@@ -137,12 +126,13 @@ public PlanNode generateTransactionalValidationPlan(ConnectionsGroup connections
137126
PlanNode addedTargets;
138127

139128
if (overrideTargetNode != null) {
140-
addedTargets = target.extend(overrideTargetNode.getPlanNode(), connectionsGroup,
129+
addedTargets = effectiveTarget.extend(overrideTargetNode.getPlanNode(), connectionsGroup,
141130
validationSettings.getDataGraph(), scope,
142131
EffectiveTarget.Extend.right,
143132
false, null);
144133
} else {
145-
addedTargets = target.getPlanNode(connectionsGroup, validationSettings.getDataGraph(), scope, false,
134+
addedTargets = effectiveTarget.getPlanNode(connectionsGroup, validationSettings.getDataGraph(), scope,
135+
false,
146136
null);
147137
}
148138

0 commit comments

Comments
 (0)