diff --git a/core/src/main/java/org/neo4j/gds/core/huge/NodeFilteredGraph.java b/core/src/main/java/org/neo4j/gds/core/huge/NodeFilteredGraph.java index bdf953c3c6..e6600da0b6 100644 --- a/core/src/main/java/org/neo4j/gds/core/huge/NodeFilteredGraph.java +++ b/core/src/main/java/org/neo4j/gds/core/huge/NodeFilteredGraph.java @@ -147,6 +147,7 @@ public int degreeWithoutParallelRelationships(long nodeId) { @Override public int degreeInverse(long nodeId) { + validateIndexInverse(); int cachedDegree = this.degreeInverseCache.get(nodeId); if (cachedDegree != NO_DEGREE) { return cachedDegree; @@ -253,6 +254,7 @@ public void forEachRelationship(long nodeId, double fallbackValue, RelationshipW @Override public void forEachInverseRelationship(long nodeId, RelationshipConsumer consumer) { + validateIndexInverse(); super.forEachInverseRelationship( filteredIdMap.toRootNodeId(nodeId), (s, t) -> filterAndConsume(s, t, consumer) @@ -265,6 +267,7 @@ public void forEachInverseRelationship( double fallbackValue, RelationshipWithPropertyConsumer consumer ) { + validateIndexInverse(); super.forEachInverseRelationship( filteredIdMap.toRootNodeId(nodeId), fallbackValue, @@ -363,6 +366,14 @@ public NodePropertyValues nodeProperties(String propertyKey) { return new FilteredNodePropertyValues.FilteredToOriginalNodePropertyValues(properties, this); } + private void validateIndexInverse() { + if (this.degreeInverseCache == null) { + throw new UnsupportedOperationException( + "Cannot access inverse relationships as this graph is not inverse indexed." + ); + } + } + private boolean filterAndConsume(long source, long target, RelationshipConsumer consumer) { if (filteredIdMap.containsRootNodeId(source) && filteredIdMap.containsRootNodeId(target)) { long internalSourceId = filteredIdMap.toFilteredNodeId(source); diff --git a/core/src/test/java/org/neo4j/gds/core/huge/NodeFilteredGraphTest.java b/core/src/test/java/org/neo4j/gds/core/huge/NodeFilteredGraphTest.java index 94548b5ddd..a204e032d2 100644 --- a/core/src/test/java/org/neo4j/gds/core/huge/NodeFilteredGraphTest.java +++ b/core/src/test/java/org/neo4j/gds/core/huge/NodeFilteredGraphTest.java @@ -39,6 +39,7 @@ import java.util.function.Function; import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; import static org.junit.jupiter.api.Assertions.assertEquals; @GdlExtension @@ -83,7 +84,8 @@ void filteredIdMapThatIncludesAllNodes() { unfilteredGraph.forEachNode(nodeId -> { long filteredNodeId = filteredGraph.toFilteredNodeId(nodeId); if (unfilteredGraph.hasLabel(nodeId, filterLabel)) { - assertThat(filteredGraph.toOriginalNodeId(filteredNodeId)).isEqualTo(unfilteredGraph.toOriginalNodeId(nodeId)); + assertThat(filteredGraph.toOriginalNodeId(filteredNodeId)) + .isEqualTo(unfilteredGraph.toOriginalNodeId(nodeId)); } else { assertThat(filteredNodeId).isEqualTo(IdMap.NOT_FOUND); } @@ -230,6 +232,24 @@ void shouldStreamRelationshipsCorrectly() { } + @Test + void throwDegreeInverseIfNotIndexed() { + var graph = GdlFactory.of("(a:A)-->(b:B)-->(:B)").build().getGraph(NodeLabel.of("B")); + + assertThatThrownBy(() -> graph.degreeInverse(0)) + .isInstanceOf(UnsupportedOperationException.class) + .hasMessageContaining("Cannot access inverse relationships as this graph is not inverse indexed."); + } + + @Test + void throwForeachInverseRelationshipIfNotIndexed() { + var graph = GdlFactory.of("(a:A)-->(b:B)-->(:B)").build().getGraph(NodeLabel.of("B")); + + assertThatThrownBy(() -> graph.forEachInverseRelationship(0, (sourceNodeId, targetNodeId) -> true)) + .isInstanceOf(UnsupportedOperationException.class) + .hasMessageContaining("Cannot access inverse relationships as this graph is not inverse indexed."); + } + Function filteredIdFunction(Graph graph) { return (variable) -> graph.toMappedNodeId(idFunction.of(variable)); }