Skip to content

Commit e4a3d92

Browse files
s1ckbreakanalysis
andcommitted
Remove result statistics for triangle count
The computation has been added by accident and its results have not been exposed via procedure results. However, in combination with the maxDegree filter, computing the statistics lead to an array index oo ex, as filtered nodes returns a triangle count of -1. Co-authored-by: Jacob Sznajdman <[email protected]>
1 parent 40dcef3 commit e4a3d92

File tree

7 files changed

+121
-69
lines changed

7 files changed

+121
-69
lines changed

proc/community/src/main/java/org/neo4j/graphalgo/triangle/TriangleCountCompanion.java

Lines changed: 3 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -23,16 +23,11 @@
2323
import org.neo4j.graphalgo.core.utils.paged.AllocationTracker;
2424
import org.neo4j.graphalgo.core.utils.paged.HugeAtomicLongArray;
2525
import org.neo4j.graphalgo.core.write.PropertyTranslator;
26-
import org.neo4j.graphalgo.result.AbstractCommunityResultBuilder;
2726
import org.neo4j.graphalgo.result.AbstractResultBuilder;
2827
import org.neo4j.graphalgo.triangle.IntersectingTriangleCount.TriangleCountResult;
29-
import org.neo4j.internal.kernel.api.procs.ProcedureCallContext;
3028

3129
import java.util.Optional;
3230

33-
import static org.neo4j.graphalgo.ElementProjection.PROJECT_ALL;
34-
import static org.neo4j.graphalgo.utils.StringFormatting.formatWithLocale;
35-
3631
final class TriangleCountCompanion {
3732

3833
static final String DESCRIPTION =
@@ -48,38 +43,19 @@ static <PROC_RESULT, CONFIG extends TriangleCountBaseConfig> AbstractResultBuild
4843
TriangleCountResultBuilder<PROC_RESULT> procResultBuilder,
4944
AlgoBaseProc.ComputationResult<IntersectingTriangleCount, IntersectingTriangleCount.TriangleCountResult, CONFIG> computeResult
5045
) {
51-
var result = Optional.ofNullable(computeResult.result())
52-
.orElse(EmptyResult.EMPTY_RESULT);
53-
54-
return procResultBuilder
55-
.withTriangleCount(result.globalTriangles())
56-
.buildHistogram()
57-
.withCommunityFunction(result.localTriangles()::get);
46+
var result = Optional.ofNullable(computeResult.result()).orElse(EmptyResult.EMPTY_RESULT);
47+
return procResultBuilder.withTriangleCount(result.globalTriangles());
5848
}
5949

60-
abstract static class TriangleCountResultBuilder<PROC_RESULT> extends AbstractCommunityResultBuilder<PROC_RESULT> {
50+
abstract static class TriangleCountResultBuilder<PROC_RESULT> extends AbstractResultBuilder<PROC_RESULT> {
6151

6252
long triangleCount = 0;
6353

64-
TriangleCountResultBuilder(ProcedureCallContext callContext, AllocationTracker tracker) {
65-
super(callContext, tracker);
66-
}
67-
6854
TriangleCountResultBuilder<PROC_RESULT> withTriangleCount(long triangleCount) {
6955
this.triangleCount = triangleCount;
7056
return this;
7157
}
7258

73-
TriangleCountResultBuilder<PROC_RESULT> buildCommunityCount() {
74-
this.buildCommunityCount = true;
75-
return this;
76-
}
77-
78-
TriangleCountResultBuilder<PROC_RESULT> buildHistogram() {
79-
this.buildHistogram = true;
80-
return this;
81-
}
82-
8359
}
8460

8561
private TriangleCountCompanion() {}

proc/community/src/main/java/org/neo4j/graphalgo/triangle/TriangleCountMutateProc.java

Lines changed: 2 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -23,11 +23,9 @@
2323
import org.neo4j.graphalgo.MutateProc;
2424
import org.neo4j.graphalgo.config.GraphCreateConfig;
2525
import org.neo4j.graphalgo.core.CypherMapWrapper;
26-
import org.neo4j.graphalgo.core.utils.paged.AllocationTracker;
2726
import org.neo4j.graphalgo.core.write.PropertyTranslator;
2827
import org.neo4j.graphalgo.result.AbstractResultBuilder;
2928
import org.neo4j.graphalgo.results.MemoryEstimateResult;
30-
import org.neo4j.internal.kernel.api.procs.ProcedureCallContext;
3129
import org.neo4j.procedure.Description;
3230
import org.neo4j.procedure.Name;
3331
import org.neo4j.procedure.Procedure;
@@ -97,10 +95,7 @@ protected PropertyTranslator<IntersectingTriangleCount.TriangleCountResult> node
9795

9896
@Override
9997
protected AbstractResultBuilder<MutateResult> resultBuilder(ComputationResult<IntersectingTriangleCount, IntersectingTriangleCount.TriangleCountResult, TriangleCountMutateConfig> computeResult) {
100-
return TriangleCountCompanion.resultBuilder(
101-
new TriangleCountMutateBuilder(callContext, computeResult.tracker()),
102-
computeResult
103-
);
98+
return TriangleCountCompanion.resultBuilder(new TriangleCountMutateBuilder(), computeResult);
10499
}
105100

106101
public static class MutateResult extends TriangleCountStatsProc.StatsResult {
@@ -131,15 +126,8 @@ public MutateResult(
131126

132127
static class TriangleCountMutateBuilder extends TriangleCountCompanion.TriangleCountResultBuilder<MutateResult> {
133128

134-
TriangleCountMutateBuilder(
135-
ProcedureCallContext callContext,
136-
AllocationTracker tracker
137-
) {
138-
super(callContext, tracker);
139-
}
140-
141129
@Override
142-
protected MutateResult buildResult() {
130+
public MutateResult build() {
143131
return new MutateResult(
144132
triangleCount,
145133
nodeCount,

proc/community/src/main/java/org/neo4j/graphalgo/triangle/TriangleCountStatsProc.java

Lines changed: 2 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -23,10 +23,8 @@
2323
import org.neo4j.graphalgo.StatsProc;
2424
import org.neo4j.graphalgo.config.GraphCreateConfig;
2525
import org.neo4j.graphalgo.core.CypherMapWrapper;
26-
import org.neo4j.graphalgo.core.utils.paged.AllocationTracker;
2726
import org.neo4j.graphalgo.result.AbstractResultBuilder;
2827
import org.neo4j.graphalgo.results.MemoryEstimateResult;
29-
import org.neo4j.internal.kernel.api.procs.ProcedureCallContext;
3028
import org.neo4j.procedure.Description;
3129
import org.neo4j.procedure.Name;
3230
import org.neo4j.procedure.Procedure;
@@ -67,10 +65,7 @@ protected void validateConfigs(
6765

6866
@Override
6967
protected AbstractResultBuilder<StatsResult> resultBuilder(ComputationResult<IntersectingTriangleCount, IntersectingTriangleCount.TriangleCountResult, TriangleCountStatsConfig> computeResult) {
70-
return TriangleCountCompanion.resultBuilder(
71-
new TriangleCountStatsBuilder(callContext, computeResult.tracker()),
72-
computeResult
73-
);
68+
return TriangleCountCompanion.resultBuilder(new TriangleCountStatsBuilder(), computeResult);
7469
}
7570

7671
@Override
@@ -119,15 +114,8 @@ public StatsResult(
119114

120115
static class TriangleCountStatsBuilder extends TriangleCountCompanion.TriangleCountResultBuilder<StatsResult> {
121116

122-
TriangleCountStatsBuilder(
123-
ProcedureCallContext callContext,
124-
AllocationTracker tracker
125-
) {
126-
super(callContext, tracker);
127-
}
128-
129117
@Override
130-
protected StatsResult buildResult() {
118+
public StatsResult build() {
131119
return new StatsResult(
132120
triangleCount,
133121
nodeCount,

proc/community/src/main/java/org/neo4j/graphalgo/triangle/TriangleCountWriteProc.java

Lines changed: 2 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -23,11 +23,9 @@
2323
import org.neo4j.graphalgo.WriteProc;
2424
import org.neo4j.graphalgo.config.GraphCreateConfig;
2525
import org.neo4j.graphalgo.core.CypherMapWrapper;
26-
import org.neo4j.graphalgo.core.utils.paged.AllocationTracker;
2726
import org.neo4j.graphalgo.core.write.PropertyTranslator;
2827
import org.neo4j.graphalgo.result.AbstractResultBuilder;
2928
import org.neo4j.graphalgo.results.MemoryEstimateResult;
30-
import org.neo4j.internal.kernel.api.procs.ProcedureCallContext;
3129
import org.neo4j.procedure.Description;
3230
import org.neo4j.procedure.Name;
3331
import org.neo4j.procedure.Procedure;
@@ -96,10 +94,7 @@ protected PropertyTranslator<IntersectingTriangleCount.TriangleCountResult> node
9694

9795
@Override
9896
protected AbstractResultBuilder<WriteResult> resultBuilder(ComputationResult<IntersectingTriangleCount, IntersectingTriangleCount.TriangleCountResult, TriangleCountWriteConfig> computeResult) {
99-
return TriangleCountCompanion.resultBuilder(
100-
new TriangleCountWriteBuilder(callContext, computeResult.tracker()),
101-
computeResult
102-
);
97+
return TriangleCountCompanion.resultBuilder(new TriangleCountWriteBuilder(), computeResult);
10398
}
10499

105100
public static class WriteResult extends TriangleCountStatsProc.StatsResult {
@@ -131,15 +126,8 @@ public WriteResult(
131126

132127
static class TriangleCountWriteBuilder extends TriangleCountCompanion.TriangleCountResultBuilder<WriteResult> {
133128

134-
TriangleCountWriteBuilder(
135-
ProcedureCallContext callContext,
136-
AllocationTracker tracker
137-
) {
138-
super(callContext, tracker);
139-
}
140-
141129
@Override
142-
protected WriteResult buildResult() {
130+
public WriteResult build() {
143131
return new WriteResult(
144132
triangleCount,
145133
nodeCount,

proc/community/src/test/java/org/neo4j/graphalgo/triangle/TriangleCountMutateProcTest.java

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,10 @@
2525
import org.neo4j.graphalgo.GraphMutationTest;
2626
import org.neo4j.graphalgo.Orientation;
2727
import org.neo4j.graphalgo.RelationshipProjection;
28+
import org.neo4j.graphalgo.TestGraph;
29+
import org.neo4j.graphalgo.api.Graph;
2830
import org.neo4j.graphalgo.core.CypherMapWrapper;
31+
import org.neo4j.graphalgo.core.loading.GraphStoreCatalog;
2932
import org.neo4j.values.storable.NumberType;
3033

3134
import java.util.List;
@@ -36,6 +39,8 @@
3639
import static org.hamcrest.Matchers.isA;
3740
import static org.neo4j.graphalgo.ElementProjection.PROJECT_ALL;
3841
import static org.neo4j.graphalgo.RelationshipType.ALL_RELATIONSHIPS;
42+
import static org.neo4j.graphalgo.TestGraph.Builder.fromGdl;
43+
import static org.neo4j.graphalgo.TestSupport.assertGraphEquals;
3944

4045
class TriangleCountMutateProcTest
4146
extends TriangleCountBaseProcTest<TriangleCountMutateConfig>
@@ -91,6 +96,59 @@ void testMutateYields() {
9196
)));
9297
}
9398

99+
@Test
100+
void testMutateWithMaxDegree() {
101+
// Add a single node and connect it to the triangle
102+
// to be able to apply the maxDegree filter.
103+
runQuery("MATCH (n) " +
104+
"WITH n LIMIT 1 " +
105+
"CREATE (d)-[:REL]->(n)");
106+
107+
var createQuery = GdsCypher.call()
108+
.loadEverything(Orientation.UNDIRECTED)
109+
.graphCreate("testGraph")
110+
.yields();
111+
112+
runQuery(createQuery);
113+
114+
var query = GdsCypher.call()
115+
.explicitCreation("testGraph")
116+
.algo("triangleCount")
117+
.mutateMode()
118+
.addParameter("mutateProperty", mutateProperty())
119+
.addParameter("maxDegree", 2)
120+
.yields();
121+
122+
assertCypherResult(query, List.of(Map.of(
123+
"globalTriangleCount", 0L,
124+
"nodeCount", 4L,
125+
"createMillis", greaterThan(-1L),
126+
"computeMillis", greaterThan(-1L),
127+
"configuration", isA(Map.class),
128+
"nodePropertiesWritten", 4L,
129+
"mutateMillis", greaterThan(-1L)
130+
)));
131+
132+
Graph actualGraph = GraphStoreCatalog.get(getUsername(), "testGraph").graphStore().getUnion();
133+
134+
assertGraphEquals(
135+
fromGdl(
136+
" (a { mutatedTriangleCount: -1 })" +
137+
", (b { mutatedTriangleCount: 0 })" +
138+
", (c { mutatedTriangleCount: 0 })" +
139+
", (d { mutatedTriangleCount: 0 })" +
140+
// Graph is UNDIRECTED, e.g. each rel twice
141+
", (a)-->(b)" +
142+
", (b)-->(a)" +
143+
", (b)-->(c)" +
144+
", (c)-->(b)" +
145+
", (a)-->(c)" +
146+
", (c)-->(a)" +
147+
", (d)-->(a)" +
148+
", (a)-->(d)"
149+
), actualGraph);
150+
}
151+
94152
@Override
95153
public Class<? extends AlgoBaseProc<IntersectingTriangleCount, IntersectingTriangleCount.TriangleCountResult, TriangleCountMutateConfig>> getProcedureClazz() {
96154
return TriangleCountMutateProc.class;

proc/community/src/test/java/org/neo4j/graphalgo/triangle/TriangleCountStatsProcTest.java

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,29 @@ void testStats() {
5151
)));
5252
}
5353

54+
@Test
55+
void testStatsWithMaxDegree() {
56+
// Add a single node and connect it to the triangle
57+
// to be able to apply the maxDegree filter.
58+
runQuery("MATCH (n) " +
59+
"WITH n LIMIT 1 " +
60+
"CREATE (d)-[:REL]->(n)");
61+
62+
var query = GdsCypher.call()
63+
.loadEverything(Orientation.UNDIRECTED)
64+
.algo("triangleCount")
65+
.statsMode()
66+
.addParameter("maxDegree", 2)
67+
.yields();
68+
69+
assertCypherResult(query, List.of(Map.of(
70+
"globalTriangleCount", 0L,
71+
"nodeCount", 4L,
72+
"createMillis", greaterThan(-1L),
73+
"computeMillis", greaterThan(-1L),
74+
"configuration", isA(Map.class)
75+
)));
76+
}
5477

5578
@Override
5679
public Class<? extends AlgoBaseProc<IntersectingTriangleCount, IntersectingTriangleCount.TriangleCountResult, TriangleCountStatsConfig>> getProcedureClazz() {

proc/community/src/test/java/org/neo4j/graphalgo/triangle/TriangleCountWriteProcTest.java

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,37 @@ void testWrite() {
8181
assertWriteResult(expectedResult, "triangles");
8282
}
8383

84+
@Test
85+
void testWriteWithMaxDegree() {
86+
var query = GdsCypher.call()
87+
.loadEverything(Orientation.UNDIRECTED)
88+
.algo("triangleCount")
89+
.writeMode()
90+
.addParameter("writeProperty", "triangles")
91+
.addParameter("maxDegree", 2)
92+
.yields();
93+
94+
assertCypherResult(query, List.of(Map.of(
95+
"globalTriangleCount", 0L,
96+
"nodeCount", 5L,
97+
"createMillis", greaterThan(-1L),
98+
"computeMillis", greaterThan(-1L),
99+
"configuration", isA(Map.class),
100+
"nodePropertiesWritten", 5L,
101+
"writeMillis", greaterThan(-1L)
102+
)));
103+
104+
Map<String, Long> expectedResult = Map.of(
105+
"a", -1L,
106+
"b", -1L,
107+
"c", -1L,
108+
"d", -1L,
109+
"e", 0L
110+
);
111+
112+
assertWriteResult(expectedResult, "triangles");
113+
}
114+
84115
@Override
85116
public Class<? extends AlgoBaseProc<IntersectingTriangleCount, IntersectingTriangleCount.TriangleCountResult, TriangleCountWriteConfig>> getProcedureClazz() {
86117
return TriangleCountWriteProc.class;

0 commit comments

Comments
 (0)