Skip to content

Commit 099646a

Browse files
committed
GH-5033: fix pushing of limits for simple ASK queries in FedX
This change makes sure to push limits for simple ASK queries with a single statement patterns into the query. The optimization is the same as applied for simple SELECT queries with a LIMIT. Rational: if the limit is not pushed, the federation engine will first fetch all data for the statement pattern and only then locally check if there is at least one, i.e it will cause performance issues and memory pressure when there are many triples matching the statement pattern (for instance millions of persons).
1 parent 1749af8 commit 099646a

2 files changed

Lines changed: 81 additions & 0 deletions

File tree

tools/federation/src/main/java/org/eclipse/rdf4j/federated/optimizer/LimitOptimizer.java

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,18 @@ public void meet(Slice node) throws OptimizationException {
6565
applicableLimitInScope = node.getLimit();
6666
}
6767
super.meet(node);
68+
69+
TupleExpr expr = node.getArg();
70+
// if the top most element is a statement (e.g. for an ASK query with single statement pattern),
71+
// i.e. no join, union or
72+
// any other complex pattern, we can push the limit
73+
// => this case typically represents a query with a single BGP
74+
if (expr instanceof FedXStatementPattern) {
75+
if (applicableLimitInScope > 0) {
76+
pushLimit((FedXStatementPattern) expr, applicableLimitInScope);
77+
}
78+
}
79+
6880
applicableLimitInScope = -1;
6981

7082
}
Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
/*******************************************************************************
2+
* Copyright (c) 2024 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+
package org.eclipse.rdf4j.federated;
12+
13+
import java.util.Arrays;
14+
15+
import org.eclipse.rdf4j.model.vocabulary.FOAF;
16+
import org.eclipse.rdf4j.query.QueryResults;
17+
import org.eclipse.rdf4j.query.TupleQuery;
18+
import org.eclipse.rdf4j.repository.Repository;
19+
import org.eclipse.rdf4j.repository.RepositoryConnection;
20+
import org.junit.jupiter.api.Assertions;
21+
import org.junit.jupiter.api.Test;
22+
23+
public class LimitTests extends SPARQLBaseTest {
24+
25+
@Test
26+
public void testLimitPushing_Select_SingleStatement() throws Exception {
27+
28+
// datsets contain both instances of foaf:Person
29+
prepareTest(
30+
Arrays.asList("/tests/data/data1.ttl", "/tests/data/data2.ttl"));
31+
32+
Repository fedxRepo = fedxRule.getRepository();
33+
34+
try (RepositoryConnection conn = fedxRepo.getConnection()) {
35+
36+
String query = "SELECT * WHERE { ?person a <" + FOAF.PERSON.stringValue() + "> } LIMIT 2";
37+
TupleQuery tq = conn.prepareTupleQuery(query);
38+
Assertions.assertEquals(2, QueryResults.asList(tq.evaluate()).size());
39+
40+
// check that the query plan contains information about limit
41+
String queryPlan = fedxRule.getFederationContext().getQueryManager().getQueryPlan(query);
42+
Assertions.assertTrue(queryPlan.contains("Upper Limit: 2"));
43+
}
44+
}
45+
46+
@Test
47+
public void testLimitPushing_Ask_SingleStatement() throws Exception {
48+
49+
// datsets contain both instances of foaf:Person
50+
prepareTest(
51+
Arrays.asList("/tests/data/data1.ttl", "/tests/data/data2.ttl"));
52+
53+
Repository fedxRepo = fedxRule.getRepository();
54+
55+
try (RepositoryConnection conn = fedxRepo.getConnection()) {
56+
57+
String query = "ASK { ?person a <" + FOAF.PERSON.stringValue() + "> }";
58+
Assertions.assertTrue(conn.prepareBooleanQuery(query).evaluate());
59+
60+
// check that the query plan contains information about limit
61+
String queryPlan = fedxRule.getFederationContext().getQueryManager().getQueryPlan(query);
62+
Assertions.assertTrue(queryPlan.contains("Upper Limit: 1"));
63+
64+
// also run a query with no backing data
65+
query = "ASK { ?organization a <" + FOAF.ORGANIZATION.stringValue() + "> }";
66+
Assertions.assertFalse(conn.prepareBooleanQuery(query).evaluate());
67+
}
68+
}
69+
}

0 commit comments

Comments
 (0)