Skip to content

Commit be12d58

Browse files
FlorentinDadamnsch
andcommitted
Fix NodeFilteredGraph::degree
Co-authored-by: Adam Schill Collberg <[email protected]>
1 parent 2684049 commit be12d58

File tree

3 files changed

+121
-5
lines changed

3 files changed

+121
-5
lines changed

core/src/main/java/org/neo4j/graphalgo/core/huge/NodeFilteredGraph.java

Lines changed: 34 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
*/
2020
package org.neo4j.graphalgo.core.huge;
2121

22+
import org.apache.commons.lang3.mutable.MutableInt;
2223
import org.neo4j.collection.primitive.PrimitiveLongIterable;
2324
import org.neo4j.collection.primitive.PrimitiveLongIterator;
2425
import org.neo4j.graphalgo.api.FilterGraph;
@@ -28,16 +29,32 @@
2829
import org.neo4j.graphalgo.api.RelationshipIntersect;
2930
import org.neo4j.graphalgo.api.RelationshipWithPropertyConsumer;
3031
import org.neo4j.graphalgo.core.loading.IdMap;
32+
import org.neo4j.graphalgo.core.utils.paged.AllocationTracker;
33+
import org.neo4j.graphalgo.core.utils.paged.HugeIntArray;
3134

3235
import java.util.Collection;
3336
import java.util.function.LongPredicate;
3437

3538
public class NodeFilteredGraph extends FilterGraph implements IdMapGraph {
3639

40+
private static final int NO_DEGREE = -1;
41+
3742
private final IdMap filteredIdMap;
43+
private long relationshipCount;
44+
private final HugeIntArray degreeCache;
45+
46+
public NodeFilteredGraph(HugeGraph originalGraph, IdMap filteredIdMap, AllocationTracker allocationTracker) {
47+
super(originalGraph);
48+
this.relationshipCount = -1;
49+
this.filteredIdMap = filteredIdMap;
50+
this.degreeCache = HugeIntArray.newArray(filteredIdMap.nodeCount(), allocationTracker);
51+
degreeCache.fill(NO_DEGREE);
52+
}
53+
54+
public NodeFilteredGraph(HugeGraph originalGraph, IdMap filteredIdMap, HugeIntArray degreeCache) {
55+
super(originalGraph);
3856

39-
public NodeFilteredGraph(HugeGraph graph, IdMap filteredIdMap) {
40-
super(graph);
57+
this.degreeCache = degreeCache;
4158
this.filteredIdMap = filteredIdMap;
4259
}
4360

@@ -68,7 +85,20 @@ public void forEachNode(LongPredicate consumer) {
6885

6986
@Override
7087
public int degree(long nodeId) {
71-
return super.degree(filteredIdMap.toOriginalNodeId(nodeId));
88+
int cachedDegree = degreeCache.get(nodeId);
89+
if (cachedDegree != NO_DEGREE) {
90+
return cachedDegree;
91+
}
92+
93+
MutableInt degree = new MutableInt();
94+
95+
forEachRelationship(nodeId, (s, t) -> {
96+
degree.increment();
97+
return true;
98+
});
99+
degreeCache.set(nodeId, degree.intValue());
100+
101+
return degree.intValue();
72102
}
73103

74104
@Override
@@ -131,7 +161,7 @@ public double relationshipProperty(long sourceNodeId, long targetNodeId) {
131161

132162
@Override
133163
public IdMapGraph concurrentCopy() {
134-
return new NodeFilteredGraph((HugeGraph) graph.concurrentCopy(), filteredIdMap);
164+
return new NodeFilteredGraph((HugeGraph) graph.concurrentCopy(), filteredIdMap, degreeCache);
135165
}
136166

137167
@Override

core/src/main/java/org/neo4j/graphalgo/core/loading/GraphStore.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -472,7 +472,7 @@ protected IdMapGraph createGraph(
472472
);
473473

474474
if (filteredNodes.isPresent()) {
475-
return new NodeFilteredGraph(initialGraph, filteredNodes.get());
475+
return new NodeFilteredGraph(initialGraph, filteredNodes.get(), tracker);
476476
} else {
477477
return initialGraph;
478478
}
Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
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.graphalgo.core.huge;
21+
22+
import org.junit.jupiter.api.AfterEach;
23+
import org.junit.jupiter.api.BeforeEach;
24+
import org.junit.jupiter.api.Test;
25+
import org.neo4j.graphalgo.NodeLabel;
26+
import org.neo4j.graphalgo.RelationshipType;
27+
import org.neo4j.graphalgo.StoreLoaderBuilder;
28+
import org.neo4j.graphalgo.TestDatabaseCreator;
29+
import org.neo4j.graphalgo.api.Graph;
30+
import org.neo4j.graphalgo.compat.GraphDbApi;
31+
import org.neo4j.graphalgo.core.loading.GraphStore;
32+
import org.neo4j.graphalgo.core.loading.NativeFactory;
33+
34+
import java.util.Optional;
35+
36+
import static java.util.Arrays.asList;
37+
import static org.junit.jupiter.api.Assertions.assertEquals;
38+
import static org.neo4j.graphalgo.QueryRunner.runQuery;
39+
40+
public class NodeFilteredGraphTest {
41+
42+
private GraphDbApi db;
43+
44+
private static final String DB_CYPHER =
45+
" CREATE" +
46+
" (a:Person)," +
47+
" (b:Ignore:Person)," +
48+
" (c:Ignore:Person)," +
49+
" (d:Person)," +
50+
" (e:Ignore)," +
51+
" (a)-[:REL]->(b)," +
52+
" (a)-[:REL]->(e)";
53+
54+
@BeforeEach
55+
void setup() {
56+
db = TestDatabaseCreator.createTestDatabase();
57+
runQuery(db, DB_CYPHER);
58+
}
59+
60+
@AfterEach
61+
void teardown() {
62+
db.shutdown();
63+
}
64+
65+
66+
@Test
67+
void filterDegree() {
68+
GraphStore graphStore = new StoreLoaderBuilder()
69+
.api(db)
70+
.nodeLabels(asList("Person", "Ignore"))
71+
.addRelationshipType("REL")
72+
.build()
73+
.graphStore(NativeFactory.class);
74+
75+
Graph graph = graphStore.getGraph(
76+
asList(NodeLabel.of("Person")),
77+
asList(RelationshipType.of("REL")),
78+
Optional.empty(),
79+
4
80+
);
81+
82+
long nodeIdOfA = graph.toMappedNodeId(0);
83+
assertEquals(1L, graph.degree(nodeIdOfA));
84+
}
85+
86+
}

0 commit comments

Comments
 (0)