Skip to content

Commit 98d8944

Browse files
authored
GH-5227: fix binding assigner optimizer in FedX (#5228)
2 parents 230a437 + 99d7ba3 commit 98d8944

2 files changed

Lines changed: 74 additions & 2 deletions

File tree

tools/federation/src/main/java/org/eclipse/rdf4j/federated/evaluation/FederationEvalStrategy.java

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,7 @@
107107
import org.eclipse.rdf4j.query.algebra.ValueExpr;
108108
import org.eclipse.rdf4j.query.algebra.Var;
109109
import org.eclipse.rdf4j.query.algebra.evaluation.QueryEvaluationStep;
110+
import org.eclipse.rdf4j.query.algebra.evaluation.QueryOptimizer;
110111
import org.eclipse.rdf4j.query.algebra.evaluation.QueryValueEvaluationStep;
111112
import org.eclipse.rdf4j.query.algebra.evaluation.ValueExprEvaluationException;
112113
import org.eclipse.rdf4j.query.algebra.evaluation.federation.FederatedService;
@@ -118,6 +119,7 @@
118119
import org.eclipse.rdf4j.query.algebra.evaluation.iterator.HashJoinIteration;
119120
import org.eclipse.rdf4j.query.algebra.evaluation.optimizer.ConstantOptimizer;
120121
import org.eclipse.rdf4j.query.algebra.evaluation.optimizer.DisjunctiveConstraintOptimizer;
122+
import org.eclipse.rdf4j.query.algebra.evaluation.optimizer.StandardQueryOptimizerPipeline;
121123
import org.eclipse.rdf4j.query.algebra.evaluation.util.QueryEvaluationUtil;
122124
import org.eclipse.rdf4j.query.algebra.helpers.TupleExprs;
123125
import org.eclipse.rdf4j.query.algebra.helpers.collectors.VarNameCollector;
@@ -147,6 +149,14 @@ public abstract class FederationEvalStrategy extends StrictEvaluationStrategy {
147149

148150
protected FederationContext federationContext;
149151

152+
/**
153+
* List of standard {@link QueryOptimizer}s applicable to federation
154+
*/
155+
private static final List<QueryOptimizer> standardOptimizers = List.of(
156+
StandardQueryOptimizerPipeline.BINDING_ASSIGNER,
157+
StandardQueryOptimizerPipeline.BINDING_SET_ASSIGNMENT_INLINER,
158+
StandardQueryOptimizerPipeline.DISJUNCTIVE_CONSTRAINT_OPTIMIZER);
159+
150160
public FederationEvalStrategy(FederationContext federationContext) {
151161
super(new org.eclipse.rdf4j.query.algebra.evaluation.TripleSource() {
152162

@@ -209,9 +219,11 @@ public TupleExpr optimize(TupleExpr expr, EvaluationStatistics evaluationStatist
209219
}
210220

211221
/* original RDF4J optimizers */
212-
new ConstantOptimizer(this).optimize(query, dataset, bindings); // maybe remove this optimizer later
222+
for (QueryOptimizer optimizer : standardOptimizers) {
223+
optimizer.optimize(query, dataset, bindings);
224+
}
213225

214-
new DisjunctiveConstraintOptimizer().optimize(query, dataset, bindings);
226+
new ConstantOptimizer(this).optimize(query, dataset, bindings); // maybe remove this optimizer later
215227

216228
/*
217229
* TODO add some generic optimizers: - FILTER ?s=1 && ?s=2 => EmptyResult - Remove variables that are not

tools/federation/src/test/java/org/eclipse/rdf4j/federated/evaluation/FederationEvalStrategyTest.java

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,23 @@
1010
*******************************************************************************/
1111
package org.eclipse.rdf4j.federated.evaluation;
1212

13+
import java.util.Arrays;
1314
import java.util.List;
15+
import java.util.Set;
16+
import java.util.stream.Collectors;
1417

1518
import org.eclipse.rdf4j.federated.SPARQLBaseTest;
19+
import org.eclipse.rdf4j.federated.cache.SourceSelectionCache;
20+
import org.eclipse.rdf4j.federated.cache.SourceSelectionCache.StatementSourceAssurance;
21+
import org.eclipse.rdf4j.federated.endpoint.Endpoint;
22+
import org.eclipse.rdf4j.federated.structures.SubQuery;
23+
import org.eclipse.rdf4j.model.util.Values;
24+
import org.eclipse.rdf4j.model.vocabulary.FOAF;
25+
import org.eclipse.rdf4j.model.vocabulary.OWL;
26+
import org.eclipse.rdf4j.model.vocabulary.RDF;
27+
import org.eclipse.rdf4j.query.TupleQuery;
28+
import org.eclipse.rdf4j.repository.Repository;
29+
import org.eclipse.rdf4j.repository.RepositoryConnection;
1630
import org.junit.jupiter.api.Assertions;
1731
import org.junit.jupiter.api.Test;
1832

@@ -46,4 +60,50 @@ public void testOptimize_SingleMember_Service() throws Exception {
4660

4761
Assertions.assertTrue(queryPlan.startsWith("QueryRoot"));
4862
}
63+
64+
@Test
65+
public void testSourceSelectionCache_setBindings() throws Exception {
66+
67+
var bob = Values.iri("http://example.com/bob");
68+
69+
List<Endpoint> endpoints = prepareTest(
70+
Arrays.asList("/tests/basic/data_emptyStore.ttl", "/tests/basic/data_emptyStore.ttl"));
71+
72+
Repository repo1 = getRepository(1);
73+
Repository repo2 = getRepository(2);
74+
75+
String repo1Id = endpoints.get(0).getId();
76+
77+
try (RepositoryConnection con = repo1.getConnection()) {
78+
con.add(bob, RDF.TYPE, FOAF.PERSON);
79+
}
80+
81+
try (RepositoryConnection con = repo2.getConnection()) {
82+
con.add(FOAF.PERSON, RDF.TYPE, OWL.CLASS);
83+
}
84+
85+
Repository fedxRepo = fedxRule.getRepository();
86+
87+
fedxRule.enableDebug();
88+
89+
try (var conn = fedxRepo.getConnection()) {
90+
91+
TupleQuery tq = conn.prepareTupleQuery("SELECT * WHERE { ?s a ?type }");
92+
tq.setBinding("s", bob);
93+
94+
try (var tqr = tq.evaluate()) {
95+
// just consume the result
96+
Assertions.assertEquals(Set.of(FOAF.PERSON),
97+
tqr.stream().map(bs -> bs.getValue("type")).collect(Collectors.toSet()));
98+
}
99+
}
100+
101+
SourceSelectionCache cache = federationContext().getSourceSelectionCache();
102+
103+
var assurance = cache.getAssurance(new SubQuery(bob, RDF.TYPE, null),
104+
federationContext().getEndpointManager().getEndpoint(repo1Id));
105+
106+
// we expect that the source selection cache can assure statements
107+
Assertions.assertEquals(StatementSourceAssurance.HAS_REMOTE_STATEMENTS, assurance);
108+
}
49109
}

0 commit comments

Comments
 (0)