Skip to content

Commit b9717d1

Browse files
Intermezzo: Use undirected validation in path finding as well.
1 parent caa467c commit b9717d1

File tree

6 files changed

+189
-23
lines changed

6 files changed

+189
-23
lines changed

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

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,13 +27,13 @@
2727
import org.neo4j.gds.api.User;
2828
import org.neo4j.gds.collections.ha.HugeLongArray;
2929
import org.neo4j.gds.collections.haa.HugeAtomicLongArray;
30+
import org.neo4j.gds.core.JobId;
3031
import org.neo4j.gds.core.loading.GraphStoreCatalogService;
3132
import org.neo4j.gds.core.loading.validation.NoAlgorithmValidation;
3233
import org.neo4j.gds.core.loading.validation.SourceNodeGraphStoreValidation;
3334
import org.neo4j.gds.core.loading.validation.SourceNodeTargetNodeGraphStoreValidation;
3435
import org.neo4j.gds.core.loading.validation.SourceNodeTargetNodesGraphStoreValidation;
3536
import org.neo4j.gds.core.loading.validation.SourceNodesGraphStoreValidation;
36-
import org.neo4j.gds.core.JobId;
3737
import org.neo4j.gds.dag.longestPath.DagLongestPathParameters;
3838
import org.neo4j.gds.dag.topologicalsort.TopologicalSortParameters;
3939
import org.neo4j.gds.dag.topologicalsort.TopologicalSortResult;
@@ -43,6 +43,7 @@
4343
import org.neo4j.gds.pathfinding.validation.KSpanningTreeGraphStoreValidation;
4444
import org.neo4j.gds.pathfinding.validation.PCSTGraphStoreValidation;
4545
import org.neo4j.gds.pathfinding.validation.RandomWalkGraphValidation;
46+
import org.neo4j.gds.pathfinding.validation.SpanningTreeGraphStoreValidation;
4647
import org.neo4j.gds.paths.astar.AStarParameters;
4748
import org.neo4j.gds.paths.bellmanford.BellmanFordParameters;
4849
import org.neo4j.gds.paths.bellmanford.BellmanFordResult;
@@ -543,7 +544,7 @@ public <TR> CompletableFuture<TR> spanningTree(
543544
graphName,
544545
graphParameters,
545546
relationshipProperty,
546-
new SourceNodeGraphStoreValidation(parameters.sourceNode()),
547+
SpanningTreeGraphStoreValidation.create(parameters.sourceNode()),
547548
Optional.empty(),
548549
user,
549550
databaseId

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

Lines changed: 22 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -24,20 +24,20 @@
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.UndirectedOnlyGraphStoreValidation;
2728
import org.neo4j.gds.utils.StringFormatting;
2829

2930
import java.util.Collection;
30-
import java.util.Set;
31-
import java.util.stream.Collectors;
32-
33-
import static org.neo4j.gds.utils.StringFormatting.formatWithLocale;
3431

3532
public class PCSTGraphStoreValidation extends GraphStoreValidation {
3633

3734
private final String prizeProperty;
35+
private final UndirectedOnlyGraphStoreValidation undirectedOnlyGraphStoreValidation;
3836

3937
public PCSTGraphStoreValidation(String prizeProperty) {
38+
4039
this.prizeProperty = prizeProperty;
40+
this.undirectedOnlyGraphStoreValidation = new UndirectedOnlyGraphStoreValidation("Prize-collecting Steiner Tree");
4141
}
4242

4343
@Override
@@ -46,22 +46,24 @@ protected void validateAlgorithmRequirements(
4646
Collection<NodeLabel> selectedLabels,
4747
Collection<RelationshipType> selectedRelationshipTypes
4848
) {
49-
if (!graphStore.schema().filterRelationshipTypes(Set.copyOf(selectedRelationshipTypes)).isUndirected()) {
50-
throw new IllegalArgumentException(formatWithLocale(
51-
"Prize-collecting Steineer requires relationship projections to be UNDIRECTED. " +
52-
"Selected relationships `%s` are not all undirected.",
53-
selectedRelationshipTypes.stream().map(RelationshipType::name).collect(Collectors.toSet())
54-
));
55-
}
49+
undirectedOnlyGraphStoreValidation.validateAlgorithmRequirements(graphStore,selectedLabels,selectedRelationshipTypes);
50+
validatePropertyExistence(graphStore,selectedLabels);
51+
validatePropertyType(graphStore);
52+
}
5653

57-
if (!graphStore.nodePropertyKeys().contains(prizeProperty)) {
58-
throw new IllegalArgumentException(
59-
StringFormatting.formatWithLocale(
60-
"Prize node property value type [%s] not found in the graph.",
61-
prizeProperty
62-
)
63-
);
64-
}
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+
}
65+
66+
void validatePropertyType(GraphStore graphStore){
6567
var valueType = graphStore.nodeProperty(prizeProperty).valueType();
6668
if (valueType == ValueType.DOUBLE) {
6769
return;
@@ -74,4 +76,5 @@ protected void validateAlgorithmRequirements(
7476
)
7577
);
7678
}
79+
7780
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
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.pathfinding.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.core.loading.validation.GraphStoreValidation;
26+
import org.neo4j.gds.core.loading.validation.SourceNodeGraphStoreValidation;
27+
import org.neo4j.gds.core.loading.validation.UndirectedOnlyGraphStoreValidation;
28+
29+
import java.util.Collection;
30+
31+
public class SpanningTreeGraphStoreValidation extends GraphStoreValidation {
32+
33+
private final SourceNodeGraphStoreValidation sourceNodeGraphStoreValidation;
34+
private final UndirectedOnlyGraphStoreValidation undirectedOnlyGraphStoreValidation;
35+
36+
37+
public static SpanningTreeGraphStoreValidation create(long sourceNode){
38+
return new SpanningTreeGraphStoreValidation(
39+
new SourceNodeGraphStoreValidation(sourceNode),
40+
new UndirectedOnlyGraphStoreValidation("Spanning Tree")
41+
);
42+
}
43+
44+
private SpanningTreeGraphStoreValidation(
45+
SourceNodeGraphStoreValidation sourceNodeGraphStoreValidation,
46+
UndirectedOnlyGraphStoreValidation undirectedOnlyGraphStoreValidation
47+
) {
48+
this.sourceNodeGraphStoreValidation = sourceNodeGraphStoreValidation;
49+
this.undirectedOnlyGraphStoreValidation = undirectedOnlyGraphStoreValidation;
50+
}
51+
52+
@Override
53+
protected void validateAlgorithmRequirements(
54+
GraphStore graphStore,
55+
Collection<NodeLabel> selectedLabels,
56+
Collection<RelationshipType> selectedRelationshipTypes
57+
) {
58+
sourceNodeGraphStoreValidation.validateAlgorithmRequirements(graphStore,selectedLabels,selectedRelationshipTypes);
59+
undirectedOnlyGraphStoreValidation.validateAlgorithmRequirements(graphStore,selectedLabels,selectedRelationshipTypes);
60+
}
61+
}

core/src/main/java/org/neo4j/gds/core/loading/validation/UndirectedOnlyGraphStoreValidation.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ public void validateAlgorithmRequirements(
4747
void validateOnlyUndirected(GraphStore graphStore,Collection<RelationshipType> selectedRelationshipTypes ){
4848
if (!graphStore.schema().filterRelationshipTypes(Set.copyOf(selectedRelationshipTypes)).isUndirected()) {
4949
throw new IllegalArgumentException(formatWithLocale(
50-
"%s requires relationship projections to be UNDIRECTED. " +
50+
"The %s algorithm requires relationship projections to be UNDIRECTED. " +
5151
"Selected relationships `%s` are not all undirected.",
5252
algorithm,
5353
selectedRelationshipTypes.stream().map(RelationshipType::name).collect(Collectors.toSet())

core/src/test/java/org/neo4j/gds/core/loading/validation/UndirectedOnlyGraphStoreValidationTest.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ void shouldThrowForDirectedSchema() {
6363

6464
var validation = new UndirectedOnlyGraphStoreValidation("foo");
6565
assertThatThrownBy(() -> validation.validateOnlyUndirected(graphStore, List.of(RelationshipType.of("REL1"))))
66-
.hasMessageContaining("foo requires relationship projections to be UNDIRECTED. " +
66+
.hasMessageContaining("The foo algorithm requires relationship projections to be UNDIRECTED. " +
6767
"Selected relationships `[REL1]` are not all undirected");
6868

6969
}
Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
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.pathfinding.validation;
21+
22+
import org.junit.jupiter.api.Test;
23+
import org.neo4j.gds.NodeLabel;
24+
import org.neo4j.gds.api.GraphStore;
25+
import org.neo4j.gds.api.nodeproperties.ValueType;
26+
import org.neo4j.gds.api.properties.nodes.NodeProperty;
27+
28+
import java.util.Set;
29+
30+
import static org.assertj.core.api.Assertions.assertThatNoException;
31+
import static org.assertj.core.api.Assertions.assertThatThrownBy;
32+
import static org.mockito.ArgumentMatchers.anySet;
33+
import static org.mockito.ArgumentMatchers.anyString;
34+
import static org.mockito.Mockito.mock;
35+
import static org.mockito.Mockito.when;
36+
37+
class PCSTGraphStoreValidationTest {
38+
39+
@Test
40+
void shouldNotThrowForExistingProperty() {
41+
var graphStore = mock(GraphStore.class);
42+
var collectionString = Set.of("p");
43+
when(graphStore.nodePropertyKeys(anySet())).thenReturn(collectionString);
44+
45+
var validation = new PCSTGraphStoreValidation("p");
46+
assertThatNoException().isThrownBy(() -> validation.validatePropertyExistence(
47+
graphStore,
48+
Set.of(NodeLabel.of("Node"))
49+
));
50+
}
51+
52+
@Test
53+
void shouldThrowForNonexistingProperty() {
54+
var graphStore = mock(GraphStore.class);
55+
var collectionString = Set.of("pNo");
56+
when(graphStore.nodePropertyKeys(anySet())).thenReturn(collectionString);
57+
58+
var validation = new PCSTGraphStoreValidation("p");
59+
assertThatThrownBy(() -> validation.validatePropertyExistence(
60+
graphStore,
61+
Set.of(NodeLabel.of("Node"))
62+
)).hasMessageContaining(
63+
"Prize node property value type [p] not found in the graph."
64+
);
65+
}
66+
67+
68+
@Test
69+
void shouldNotThrowForValidPropertyType() {
70+
var graphStore = mock(GraphStore.class);
71+
var nodeProperty = mock(NodeProperty.class);
72+
when(nodeProperty.valueType()).thenReturn(ValueType.DOUBLE);
73+
when(graphStore.nodeProperty(anyString())).thenReturn(nodeProperty);
74+
75+
var validation = new PCSTGraphStoreValidation("p");
76+
77+
assertThatNoException().isThrownBy(() -> validation.validatePropertyType(
78+
graphStore
79+
));
80+
81+
82+
}
83+
84+
@Test
85+
void shouldThrowForInvalidType() {
86+
var graphStore = mock(GraphStore.class);
87+
var nodeProperty = mock(NodeProperty.class);
88+
when(nodeProperty.valueType()).thenReturn(ValueType.FLOAT_ARRAY);
89+
when(graphStore.nodeProperty(anyString())).thenReturn(nodeProperty);
90+
91+
92+
var validation = new PCSTGraphStoreValidation("p");
93+
94+
assertThatThrownBy(() -> validation.validatePropertyType(
95+
graphStore
96+
))
97+
.hasMessageContaining("Unsupported node property value type [FLOAT_ARRAY]. Value type required: [DOUBLE]");
98+
99+
}
100+
101+
}

0 commit comments

Comments
 (0)