Skip to content

Commit 886da1f

Browse files
Add conductance to business facade + create nodeProperty existence validation classes
1 parent b9717d1 commit 886da1f

File tree

8 files changed

+357
-50
lines changed

8 files changed

+357
-50
lines changed

algorithms-compute-business-facade/src/main/java/org/neo4j/gds/community/CommunityComputeBusinessFacade.java

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,8 +28,11 @@
2828
import org.neo4j.gds.cliqueCounting.CliqueCountingResult;
2929
import org.neo4j.gds.cliquecounting.CliqueCountingParameters;
3030
import org.neo4j.gds.community.validation.ApproxMaxKCutValidation;
31+
import org.neo4j.gds.conductance.ConductanceParameters;
32+
import org.neo4j.gds.conductance.ConductanceResult;
3133
import org.neo4j.gds.core.JobId;
3234
import org.neo4j.gds.core.loading.GraphStoreCatalogService;
35+
import org.neo4j.gds.core.loading.validation.NodePropertyAnyExistsGraphStoreValidation;
3336
import org.neo4j.gds.core.loading.validation.UndirectedOnlyGraphStoreValidation;
3437
import org.neo4j.gds.result.TimedAlgorithmResult;
3538
import org.neo4j.gds.results.ResultTransformerBuilder;
@@ -119,4 +122,34 @@ public <TR> CompletableFuture<TR> cliqueCounting(
119122
).thenApply(resultTransformerBuilder.build(graphResources));
120123
}
121124

125+
public <TR> CompletableFuture<TR> conductance(
126+
GraphName graphName,
127+
GraphParameters graphParameters,
128+
Optional<String> relationshipProperty,
129+
ConductanceParameters parameters,
130+
JobId jobId,
131+
boolean logProgress,
132+
ResultTransformerBuilder<TimedAlgorithmResult<ConductanceResult>, TR> resultTransformerBuilder
133+
) {
134+
// Fetch the Graph the algorithm will operate on
135+
var graphResources = graphStoreCatalogService.fetchGraphResources(
136+
graphName,
137+
graphParameters,
138+
relationshipProperty,
139+
new NodePropertyAnyExistsGraphStoreValidation("communityProperty"),
140+
Optional.empty(),
141+
user,
142+
databaseId
143+
);
144+
var graph = graphResources.graph();
145+
146+
return computeFacade.conductance(
147+
graph,
148+
parameters,
149+
jobId,
150+
logProgress
151+
152+
).thenApply(resultTransformerBuilder.build(graphResources));
153+
}
154+
122155
}

algorithms-compute-business-facade/src/main/java/org/neo4j/gds/pathfinding/PathFindingComputeBusinessFacade.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -397,7 +397,7 @@ public <TR> CompletableFuture<TR> pcst(
397397
graphName,
398398
graphParameters,
399399
Optional.empty(),
400-
new PCSTGraphStoreValidation(parameters.prizeProperty()),
400+
PCSTGraphStoreValidation.create(parameters.prizeProperty()),
401401
Optional.empty(),
402402
user,
403403
databaseId

algorithms-compute-business-facade/src/main/java/org/neo4j/gds/pathfinding/validation/PCSTGraphStoreValidation.java

Lines changed: 23 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
import org.neo4j.gds.api.GraphStore;
2525
import org.neo4j.gds.api.nodeproperties.ValueType;
2626
import org.neo4j.gds.core.loading.validation.GraphStoreValidation;
27+
import org.neo4j.gds.core.loading.validation.NodePropertyAllExistsGraphStoreValidation;
2728
import org.neo4j.gds.core.loading.validation.UndirectedOnlyGraphStoreValidation;
2829
import org.neo4j.gds.utils.StringFormatting;
2930

@@ -33,11 +34,30 @@ public class PCSTGraphStoreValidation extends GraphStoreValidation {
3334

3435
private final String prizeProperty;
3536
private final UndirectedOnlyGraphStoreValidation undirectedOnlyGraphStoreValidation;
37+
private final NodePropertyAllExistsGraphStoreValidation nodePropertyAllExistsGraphStoreValidation;
3638

37-
public PCSTGraphStoreValidation(String prizeProperty) {
3839

40+
public PCSTGraphStoreValidation(
41+
String prizeProperty,
42+
UndirectedOnlyGraphStoreValidation undirectedOnlyGraphStoreValidation,
43+
NodePropertyAllExistsGraphStoreValidation nodePropertyAllExistsGraphStoreValidation
44+
) {
3945
this.prizeProperty = prizeProperty;
40-
this.undirectedOnlyGraphStoreValidation = new UndirectedOnlyGraphStoreValidation("Prize-collecting Steiner Tree");
46+
this.undirectedOnlyGraphStoreValidation = undirectedOnlyGraphStoreValidation;
47+
this.nodePropertyAllExistsGraphStoreValidation = nodePropertyAllExistsGraphStoreValidation;
48+
}
49+
50+
public static PCSTGraphStoreValidation create(String prizeProperty) {
51+
52+
var nodePropertyAllExistsGraphStoreValidation = new NodePropertyAllExistsGraphStoreValidation(prizeProperty);
53+
var undirectedOnlyGraphStoreValidation = new UndirectedOnlyGraphStoreValidation("Prize-collecting Steiner Tree");
54+
55+
return new PCSTGraphStoreValidation(
56+
prizeProperty,
57+
undirectedOnlyGraphStoreValidation,
58+
nodePropertyAllExistsGraphStoreValidation
59+
60+
);
4161
}
4262

4363
@Override
@@ -47,21 +67,10 @@ protected void validateAlgorithmRequirements(
4767
Collection<RelationshipType> selectedRelationshipTypes
4868
) {
4969
undirectedOnlyGraphStoreValidation.validateAlgorithmRequirements(graphStore,selectedLabels,selectedRelationshipTypes);
50-
validatePropertyExistence(graphStore,selectedLabels);
70+
nodePropertyAllExistsGraphStoreValidation.validateAlgorithmRequirements(graphStore,selectedLabels,selectedRelationshipTypes);
5171
validatePropertyType(graphStore);
5272
}
5373

54-
void validatePropertyExistence(GraphStore graphStore, Collection<NodeLabel> selectedLabels){
55-
if (!graphStore.nodePropertyKeys(selectedLabels).contains(prizeProperty)) {
56-
throw new IllegalArgumentException(
57-
StringFormatting.formatWithLocale(
58-
"Prize node property value type [%s] not found in the graph.",
59-
prizeProperty
60-
)
61-
);
62-
}
63-
64-
}
6574

6675
void validatePropertyType(GraphStore graphStore){
6776
var valueType = graphStore.nodeProperty(prizeProperty).valueType();
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
/*
2+
* Copyright (c) "Neo4j"
3+
* Neo4j Sweden AB [http://neo4j.com]
4+
*
5+
* This file is part of Neo4j.
6+
*
7+
* Neo4j is free software: you can redistribute it and/or modify
8+
* it under the terms of the GNU General Public License as published by
9+
* the Free Software Foundation, either version 3 of the License, or
10+
* (at your option) any later version.
11+
*
12+
* This program is distributed in the hope that it will be useful,
13+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
14+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15+
* GNU General Public License for more details.
16+
*
17+
* You should have received a copy of the GNU General Public License
18+
* along with this program. If not, see <http://www.gnu.org/licenses/>.
19+
*/
20+
package org.neo4j.gds.core.loading.validation;
21+
22+
import org.neo4j.gds.NodeLabel;
23+
import org.neo4j.gds.RelationshipType;
24+
import org.neo4j.gds.api.GraphStore;
25+
import org.neo4j.gds.utils.StringFormatting;
26+
27+
import java.util.Collection;
28+
29+
public class NodePropertyAllExistsGraphStoreValidation extends GraphStoreValidation {
30+
31+
private final String nodeProperty;
32+
33+
public NodePropertyAllExistsGraphStoreValidation(String nodeProperty) {this.nodeProperty = nodeProperty;}
34+
35+
@Override
36+
public void validateAlgorithmRequirements(
37+
GraphStore graphStore,
38+
Collection<NodeLabel> selectedLabels,
39+
Collection<RelationshipType> selectedRelationshipTypes
40+
) {
41+
validatePropertyExists(graphStore,selectedLabels);
42+
}
43+
44+
void validatePropertyExists(GraphStore graphStore,
45+
Collection<NodeLabel> selectedLabels){
46+
if (!graphStore.nodePropertyKeys(selectedLabels).contains(nodeProperty)) {
47+
throw new IllegalArgumentException(
48+
StringFormatting.formatWithLocale(
49+
"Node property [%s] not found in the graph.",
50+
nodeProperty
51+
)
52+
);
53+
}
54+
}
55+
}
Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
/*
2+
* Copyright (c) "Neo4j"
3+
* Neo4j Sweden AB [http://neo4j.com]
4+
*
5+
* This file is part of Neo4j.
6+
*
7+
* Neo4j is free software: you can redistribute it and/or modify
8+
* it under the terms of the GNU General Public License as published by
9+
* the Free Software Foundation, either version 3 of the License, or
10+
* (at your option) any later version.
11+
*
12+
* This program is distributed in the hope that it will be useful,
13+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
14+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15+
* GNU General Public License for more details.
16+
*
17+
* You should have received a copy of the GNU General Public License
18+
* along with this program. If not, see <http://www.gnu.org/licenses/>.
19+
*/
20+
package org.neo4j.gds.core.loading.validation;
21+
22+
import org.neo4j.gds.NodeLabel;
23+
import org.neo4j.gds.RelationshipType;
24+
import org.neo4j.gds.api.GraphStore;
25+
import org.neo4j.gds.utils.StringJoining;
26+
27+
import java.util.Collection;
28+
29+
import static org.neo4j.gds.utils.StringFormatting.formatWithLocale;
30+
31+
public class NodePropertyAnyExistsGraphStoreValidation extends GraphStoreValidation {
32+
33+
private final String nodeProperty;
34+
35+
public NodePropertyAnyExistsGraphStoreValidation(String nodeProperty) {this.nodeProperty = nodeProperty;}
36+
37+
@Override
38+
public void validateAlgorithmRequirements(
39+
GraphStore graphStore,
40+
Collection<NodeLabel> selectedLabels,
41+
Collection<RelationshipType> selectedRelationshipTypes
42+
) {
43+
validatePropertyExists(graphStore,selectedLabels);
44+
}
45+
46+
void validatePropertyExists(GraphStore graphStore,
47+
Collection<NodeLabel> selectedLabels){
48+
if (selectedLabels
49+
.stream()
50+
.anyMatch(label -> graphStore.nodePropertyKeys(label).contains(nodeProperty))) {
51+
return;
52+
}
53+
throw new IllegalArgumentException(formatWithLocale(
54+
"Node Property `%s` is not present for any requested node labels. Requested labels: %s. Labels with `%1$s` present: %s",
55+
nodeProperty,
56+
StringJoining.join(selectedLabels.stream().map(NodeLabel::name)),
57+
StringJoining.join(graphStore
58+
.nodeLabels()
59+
.stream()
60+
.filter(label -> graphStore.nodePropertyKeys(label).contains(nodeProperty))
61+
.map(NodeLabel::name))
62+
));
63+
}
64+
}
Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
/*
2+
* Copyright (c) "Neo4j"
3+
* Neo4j Sweden AB [http://neo4j.com]
4+
*
5+
* This file is part of Neo4j.
6+
*
7+
* Neo4j is free software: you can redistribute it and/or modify
8+
* it under the terms of the GNU General Public License as published by
9+
* the Free Software Foundation, either version 3 of the License, or
10+
* (at your option) any later version.
11+
*
12+
* This program is distributed in the hope that it will be useful,
13+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
14+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15+
* GNU General Public License for more details.
16+
*
17+
* You should have received a copy of the GNU General Public License
18+
* along with this program. If not, see <http://www.gnu.org/licenses/>.
19+
*/
20+
package org.neo4j.gds.core.loading.validation;
21+
22+
import org.junit.jupiter.api.Test;
23+
import org.mockito.ArgumentMatchers;
24+
import org.neo4j.gds.NodeLabel;
25+
import org.neo4j.gds.api.GraphStore;
26+
27+
import java.util.Set;
28+
29+
import static org.assertj.core.api.Assertions.assertThatNoException;
30+
import static org.assertj.core.api.Assertions.assertThatThrownBy;
31+
import static org.mockito.ArgumentMatchers.anySet;
32+
import static org.mockito.Mockito.doCallRealMethod;
33+
import static org.mockito.Mockito.mock;
34+
import static org.mockito.Mockito.when;
35+
36+
class NodePropertyAllExistsGraphStoreValidationTest {
37+
38+
@Test
39+
void shouldNotThrowForExistingProperty() {
40+
var graphStore = mock(GraphStore.class);
41+
var collectionString = Set.of("p");
42+
when(graphStore.nodePropertyKeys(ArgumentMatchers.any(NodeLabel.class))).thenReturn(collectionString);
43+
doCallRealMethod().when(graphStore).nodePropertyKeys(anySet());
44+
45+
var validation = new NodePropertyAllExistsGraphStoreValidation("p");
46+
assertThatNoException().isThrownBy(() -> validation.validatePropertyExists(
47+
graphStore,
48+
Set.of(NodeLabel.of("Node"))
49+
));
50+
}
51+
52+
@Test
53+
void shouldThrowForNonexistingPropertyInSomeLabels() {
54+
var graphStore = mock(GraphStore.class);
55+
var collectionString1 = Set.of("pNo");
56+
var collectionString2 = Set.of("p");
57+
58+
var nodeLabel1 = NodeLabel.of("Node");
59+
var nodeLabel2 = NodeLabel.of("Node1");
60+
when(graphStore.nodePropertyKeys(ArgumentMatchers.eq(nodeLabel1))).thenReturn(collectionString1);
61+
when(graphStore.nodePropertyKeys(ArgumentMatchers.eq(nodeLabel2))).thenReturn(collectionString2);
62+
doCallRealMethod().when(graphStore).nodePropertyKeys(anySet());
63+
64+
var validation = new NodePropertyAllExistsGraphStoreValidation("p");
65+
assertThatThrownBy(() -> validation.validatePropertyExists(
66+
graphStore,
67+
Set.of(nodeLabel1,nodeLabel2)
68+
)).hasMessageContaining(
69+
"Node property [p] not found in the graph"
70+
);
71+
}
72+
73+
@Test
74+
void shouldThrowForNonexistingPropertyInEveryLabel() {
75+
var graphStore = mock(GraphStore.class);
76+
var collectionString = Set.of("pNo");
77+
78+
var nodeLabel1 = NodeLabel.of("Node");
79+
var nodeLabel2 = NodeLabel.of("Node1");
80+
when(graphStore.nodePropertyKeys(ArgumentMatchers.eq(nodeLabel1))).thenReturn(collectionString);
81+
when(graphStore.nodePropertyKeys(ArgumentMatchers.eq(nodeLabel2))).thenReturn(collectionString);
82+
doCallRealMethod().when(graphStore).nodePropertyKeys(anySet());
83+
84+
var validation = new NodePropertyAllExistsGraphStoreValidation("p");
85+
assertThatThrownBy(() -> validation.validatePropertyExists(
86+
graphStore,
87+
Set.of(nodeLabel1,nodeLabel2)
88+
)).hasMessageContaining(
89+
"Node property [p] not found in the graph"
90+
);
91+
}
92+
93+
}

0 commit comments

Comments
 (0)