Skip to content

Commit af17bfa

Browse files
authored
GH-5229: fix left bind join in FedX for single binding input (#5230)
2 parents fbf6bea + 1db80b5 commit af17bfa

2 files changed

Lines changed: 79 additions & 4 deletions

File tree

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

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -953,10 +953,6 @@ public abstract CloseableIteration<BindingSet> evaluateGroupedCheck(
953953
*/
954954
public CloseableIteration<BindingSet> evaluateLeftBoundJoinStatementPattern(
955955
StatementTupleExpr stmt, final List<BindingSet> bindings) throws QueryEvaluationException {
956-
// we can omit the bound join handling
957-
if (bindings.size() == 1) {
958-
return evaluate(stmt, bindings.get(0));
959-
}
960956

961957
FilterValueExpr filterExpr = null;
962958
if (stmt instanceof FilterTuple) {

tools/federation/src/test/java/org/eclipse/rdf4j/federated/BindLeftJoinTests.java

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@
1414
import java.util.Set;
1515

1616
import org.eclipse.rdf4j.common.iteration.Iterations;
17+
import org.eclipse.rdf4j.federated.endpoint.Endpoint;
18+
import org.eclipse.rdf4j.federated.structures.SubQuery;
1719
import org.eclipse.rdf4j.model.util.Values;
1820
import org.eclipse.rdf4j.model.vocabulary.FOAF;
1921
import org.eclipse.rdf4j.model.vocabulary.OWL;
@@ -339,4 +341,81 @@ public void test_leftBindJoin_emptyOptional(boolean bindLeftJoinOptimizationEnab
339341
}
340342
}
341343

344+
@ParameterizedTest
345+
@ValueSource(booleans = { true, false })
346+
public void test_leftBindJoin_emptyLeftArgumentAsExclusiveGroup(boolean bindLeftJoinOptimizationEnabled)
347+
throws Exception {
348+
349+
var endpoints = prepareTest(
350+
Arrays.asList("/tests/basic/data_emptyStore.ttl", "/tests/basic/data_emptyStore.ttl"));
351+
352+
Repository repo1 = getRepository(1);
353+
Repository repo2 = getRepository(2);
354+
355+
Repository fedxRepo = fedxRule.getRepository();
356+
357+
fedxRule.setConfig(config -> {
358+
config.withBoundJoinBlockSize(10);
359+
config.withEnableOptionalAsBindJoin(bindLeftJoinOptimizationEnabled);
360+
});
361+
362+
// add a person
363+
try (RepositoryConnection conn = repo1.getConnection()) {
364+
var p = Values.iri("http://ex.com/p1");
365+
var otherP = Values.iri("http://other.com/p1");
366+
conn.add(p, OWL.SAMEAS, otherP);
367+
}
368+
369+
// add name for person 1
370+
try (RepositoryConnection conn = repo2.getConnection()) {
371+
var otherP = Values.iri("http://other.com/p1");
372+
conn.add(otherP, FOAF.NAME, Values.literal("Person 1"));
373+
}
374+
375+
// mark that repo2 for some reason has foaf:age statements (e.g. old cache entry)
376+
Endpoint repo2Endpoint = endpoints.get(1);
377+
federationContext().getSourceSelectionCache()
378+
.updateInformation(new SubQuery(null, FOAF.AGE, null), repo2Endpoint, true);
379+
380+
fedxRule.enableDebug();
381+
382+
try {
383+
// run query which joins results from multiple repos
384+
// the age does not exist for any person
385+
try (RepositoryConnection conn = fedxRepo.getConnection()) {
386+
String query = "PREFIX foaf: <http://xmlns.com/foaf/0.1/> " +
387+
"SELECT * WHERE { "
388+
+ " ?person owl:sameAs ?otherPerson . "
389+
+ " OPTIONAL { ?otherPerson foaf:age ?age . } " // age does not exist, however is marked as
390+
// ExclusiveStatement
391+
+ "}";
392+
393+
TupleQuery tupleQuery = conn.prepareTupleQuery(query);
394+
try (TupleQueryResult tqr = tupleQuery.evaluate()) {
395+
var bindings = Iterations.asList(tqr);
396+
397+
Assertions.assertEquals(1, bindings.size());
398+
399+
for (int i = 1; i <= 1; i++) {
400+
var p = Values.iri("http://ex.com/p" + i);
401+
var otherP = Values.iri("http://other.com/p" + i);
402+
403+
// find the bindingset for the person in the unordered result
404+
BindingSet bs = bindings.stream()
405+
.filter(b -> b.getValue("person").equals(p))
406+
.findFirst()
407+
.orElseThrow();
408+
409+
Assertions.assertEquals(otherP, bs.getValue("otherPerson"));
410+
411+
Assertions.assertEquals(otherP, bs.getValue("otherPerson"));
412+
Assertions.assertFalse(bs.hasBinding("age"));
413+
}
414+
}
415+
}
416+
417+
} finally {
418+
fedxRepo.shutDown();
419+
}
420+
}
342421
}

0 commit comments

Comments
 (0)