Skip to content

Commit

Permalink
GH-5033: fix pushing of limits for simple ASK queries in FedX
Browse files Browse the repository at this point in the history
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).
  • Loading branch information
aschwarte10 committed Jun 18, 2024
1 parent 1749af8 commit 099646a
Show file tree
Hide file tree
Showing 2 changed files with 81 additions and 0 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,18 @@ public void meet(Slice node) throws OptimizationException {
applicableLimitInScope = node.getLimit();
}
super.meet(node);

TupleExpr expr = node.getArg();
// if the top most element is a statement (e.g. for an ASK query with single statement pattern),
// i.e. no join, union or
// any other complex pattern, we can push the limit
// => this case typically represents a query with a single BGP
if (expr instanceof FedXStatementPattern) {
if (applicableLimitInScope > 0) {
pushLimit((FedXStatementPattern) expr, applicableLimitInScope);
}
}

applicableLimitInScope = -1;

}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
/*******************************************************************************
* Copyright (c) 2024 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.
*
* SPDX-License-Identifier: BSD-3-Clause
*******************************************************************************/
package org.eclipse.rdf4j.federated;

import java.util.Arrays;

import org.eclipse.rdf4j.model.vocabulary.FOAF;
import org.eclipse.rdf4j.query.QueryResults;
import org.eclipse.rdf4j.query.TupleQuery;
import org.eclipse.rdf4j.repository.Repository;
import org.eclipse.rdf4j.repository.RepositoryConnection;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;

public class LimitTests extends SPARQLBaseTest {

@Test
public void testLimitPushing_Select_SingleStatement() throws Exception {

// datsets contain both instances of foaf:Person
prepareTest(
Arrays.asList("/tests/data/data1.ttl", "/tests/data/data2.ttl"));

Repository fedxRepo = fedxRule.getRepository();

try (RepositoryConnection conn = fedxRepo.getConnection()) {

String query = "SELECT * WHERE { ?person a <" + FOAF.PERSON.stringValue() + "> } LIMIT 2";
TupleQuery tq = conn.prepareTupleQuery(query);
Assertions.assertEquals(2, QueryResults.asList(tq.evaluate()).size());

// check that the query plan contains information about limit
String queryPlan = fedxRule.getFederationContext().getQueryManager().getQueryPlan(query);
Assertions.assertTrue(queryPlan.contains("Upper Limit: 2"));
}
}

@Test
public void testLimitPushing_Ask_SingleStatement() throws Exception {

// datsets contain both instances of foaf:Person
prepareTest(
Arrays.asList("/tests/data/data1.ttl", "/tests/data/data2.ttl"));

Repository fedxRepo = fedxRule.getRepository();

try (RepositoryConnection conn = fedxRepo.getConnection()) {

String query = "ASK { ?person a <" + FOAF.PERSON.stringValue() + "> }";
Assertions.assertTrue(conn.prepareBooleanQuery(query).evaluate());

// check that the query plan contains information about limit
String queryPlan = fedxRule.getFederationContext().getQueryManager().getQueryPlan(query);
Assertions.assertTrue(queryPlan.contains("Upper Limit: 1"));

// also run a query with no backing data
query = "ASK { ?organization a <" + FOAF.ORGANIZATION.stringValue() + "> }";
Assertions.assertFalse(conn.prepareBooleanQuery(query).evaluate());
}
}
}

0 comments on commit 099646a

Please sign in to comment.