Skip to content

Commit bdd715d

Browse files
Mats-SXknutwalkersoerenreichardt
committed
Fix cypher projection query row estimation bug
Co-authored-by: Paul Horn <paul.horn@neotechnology.com> Co-authored-by: Sören Reichardt <soren.reichardt@neo4j.com>
1 parent 6174478 commit bdd715d

File tree

6 files changed

+47
-10
lines changed

6 files changed

+47
-10
lines changed

cypher-aggregation/build.gradle

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ dependencies {
3030
implementation project(':neo4j-values')
3131
implementation project(':progress-tracking')
3232
implementation project(':string-formatting')
33+
implementation project(':transaction')
3334
implementation project(':triplet-graph-builder')
3435

3536

cypher-aggregation/src/integrationTest/java/org/neo4j/gds/projection/CypherAggregationTest.java

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
import org.junit.jupiter.params.provider.CsvSource;
2929
import org.junit.jupiter.params.provider.MethodSource;
3030
import org.junit.jupiter.params.provider.ValueSource;
31+
import org.neo4j.configuration.GraphDatabaseSettings;
3132
import org.neo4j.exceptions.KernelException;
3233
import org.neo4j.gds.BaseProcTest;
3334
import org.neo4j.gds.BaseTest;
@@ -55,6 +56,8 @@
5556
import org.neo4j.kernel.api.CypherScope;
5657
import org.neo4j.kernel.api.procedure.CallableUserAggregationFunction;
5758
import org.neo4j.kernel.api.procedure.GlobalProcedures;
59+
import org.neo4j.test.TestDatabaseManagementServiceBuilder;
60+
import org.neo4j.test.extension.ExtensionCallback;
5861

5962
import java.util.List;
6063
import java.util.Map;
@@ -1218,6 +1221,29 @@ void testLargerGraphSize() {
12181221
}
12191222
}
12201223

1224+
@Nested
1225+
class EstimateRowsTest extends BaseTest {
1226+
1227+
@Override
1228+
@ExtensionCallback
1229+
protected void configuration(TestDatabaseManagementServiceBuilder builder) {
1230+
super.configuration(builder.setConfig(GraphDatabaseSettings.log_queries_obfuscate_literals, true));
1231+
}
1232+
1233+
@Test
1234+
void explainingWithObfuscatedLiteralsDoesntRuinTheDay() {
1235+
assertThatCode(() -> runQuery("RETURN gds.graph.project('g', 0, 1)")).doesNotThrowAnyException();
1236+
}
1237+
1238+
@Test
1239+
void notLiterals() {
1240+
assertThatCode(() -> runQuery(
1241+
"RETURN gds.graph.project($g, $x, $x)",
1242+
Map.of("g", "g", "x", 0)
1243+
)).doesNotThrowAnyException();
1244+
}
1245+
}
1246+
12211247
@Nested
12221248
class InverseGraphTest extends BaseTest {
12231249

cypher-aggregation/src/main/java/org/neo4j/gds/projection/CypherAggregation.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
import org.neo4j.gds.core.utils.progress.TaskStore;
2929
import org.neo4j.gds.logging.LogAdapter;
3030
import org.neo4j.gds.metrics.MetricsFacade;
31+
import org.neo4j.gds.transaction.DatabaseTransactionContext;
3132
import org.neo4j.internal.kernel.api.exceptions.ProcedureException;
3233
import org.neo4j.internal.kernel.api.procs.Neo4jTypes;
3334
import org.neo4j.internal.kernel.api.procs.QualifiedName;
@@ -112,7 +113,7 @@ public UserAggregationReducer createReducer(Context ctx) throws ProcedureExcepti
112113
? WriteMode.NONE
113114
: WriteMode.LOCAL;
114115

115-
var queryEstimator = QueryEstimator.fromTransaction(transaction);
116+
var queryEstimator = QueryEstimator.fromTransaction(DatabaseTransactionContext.of(databaseService, transaction));
116117

117118
return new ProductGraphAggregator(
118119
DatabaseId.of(databaseService.databaseName()),

cypher-aggregation/src/main/java/org/neo4j/gds/projection/QueryEstimator.java

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -20,12 +20,12 @@
2020
package org.neo4j.gds.projection;
2121

2222
import org.neo4j.gds.core.utils.progress.tasks.Task;
23-
import org.neo4j.graphdb.Transaction;
23+
import org.neo4j.gds.transaction.TransactionContext;
2424

2525
public interface QueryEstimator {
2626
int estimateRows(String query);
2727

28-
static QueryEstimator fromTransaction(Transaction transaction) {
28+
static QueryEstimator fromTransaction(TransactionContext transaction) {
2929
return new TxQueryEstimator(transaction);
3030
}
3131

@@ -35,14 +35,14 @@ static QueryEstimator empty() {
3535
}
3636

3737
final class TxQueryEstimator implements QueryEstimator {
38-
private final Transaction transaction;
38+
private final TransactionContext transactionContext;
3939

40-
TxQueryEstimator(Transaction transaction) {
41-
this.transaction = transaction;
40+
TxQueryEstimator(TransactionContext transactionContext) {
41+
this.transactionContext = transactionContext;
4242
}
4343

4444
@Override
4545
public int estimateRows(String query) {
46-
return QueryRowEstimationUtil.estimatedRows(transaction, query);
46+
return QueryRowEstimationUtil.estimatedRows(transactionContext, query);
4747
}
4848
}

cypher-aggregation/src/main/java/org/neo4j/gds/projection/QueryRowEstimationUtil.java

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,8 @@
2020
package org.neo4j.gds.projection;
2121

2222
import org.neo4j.gds.core.utils.progress.tasks.Task;
23+
import org.neo4j.gds.transaction.TransactionContext;
2324
import org.neo4j.graphdb.ExecutionPlanDescription;
24-
import org.neo4j.graphdb.Transaction;
2525

2626
import java.util.Optional;
2727

@@ -34,9 +34,11 @@ private QueryRowEstimationUtil() {}
3434
* of the cypher aggregation node. This child node contains the estimated number of rows that
3535
* will be returned by the query.
3636
*/
37-
static int estimatedRows(Transaction tx, String query) {
38-
try {
37+
static int estimatedRows(TransactionContext transactionContext, String query) {
38+
//noinspection resource
39+
try (var tx = transactionContext.fork().transaction()) {
3940
var executionPlan = tx.execute(explainQuery(query)).getExecutionPlanDescription();
41+
tx.commit();
4042
var aggregationChild = findChildOfRemoteAggregation(executionPlan);
4143
return aggregationChild
4244
.map(child -> ((Number) child.getArguments().get("EstimatedRows")).intValue())

transaction/src/main/java/org/neo4j/gds/transaction/TransactionContext.java

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,13 @@ public KernelTransaction kernelTransaction() {
106106
return tx.kernelTransaction();
107107
}
108108

109+
/**
110+
* @return The current {@link org.neo4j.graphdb.Transaction}.
111+
*/
112+
public Transaction transaction() {
113+
return tx;
114+
}
115+
109116
/**
110117
* Closes the underlying transaction.
111118
*/

0 commit comments

Comments
 (0)