Skip to content
This repository was archived by the owner on Apr 22, 2020. It is now read-only.

Commit 816dc4f

Browse files
authored
3.4 degree centrality (#719)
* [wip] degree centrality * test incoming degrees * both centrality * weighted degree centrality * weighted outgoing * weighted test * fix graphview degree * temporarily only run this on heavy and huge
1 parent 5b05643 commit 816dc4f

File tree

4 files changed

+586
-0
lines changed

4 files changed

+586
-0
lines changed
Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,109 @@
1+
package org.neo4j.graphalgo.impl;
2+
3+
import org.neo4j.graphalgo.api.Graph;
4+
import org.neo4j.graphalgo.core.utils.ParallelUtil;
5+
import org.neo4j.graphalgo.core.utils.ProgressLogger;
6+
import org.neo4j.graphalgo.impl.betweenness.BetweennessCentrality;
7+
import org.neo4j.graphdb.Direction;
8+
9+
import java.util.ArrayList;
10+
import java.util.concurrent.ExecutorService;
11+
import java.util.concurrent.Future;
12+
import java.util.concurrent.atomic.AtomicInteger;
13+
import java.util.stream.IntStream;
14+
import java.util.stream.Stream;
15+
16+
public class DegreeCentrality extends Algorithm<DegreeCentrality> {
17+
private final int nodeCount;
18+
private Direction direction;
19+
private Graph graph;
20+
private final ExecutorService executor;
21+
private final int concurrency;
22+
private volatile AtomicInteger nodeQueue = new AtomicInteger();
23+
private int[] degrees;
24+
25+
public DegreeCentrality(
26+
Graph graph,
27+
ExecutorService executor,
28+
int concurrency,
29+
Direction direction
30+
) {
31+
32+
this.graph = graph;
33+
this.executor = executor;
34+
this.concurrency = concurrency;
35+
nodeCount = Math.toIntExact(graph.nodeCount());
36+
this.direction = direction;
37+
degrees = new int[nodeCount];
38+
}
39+
40+
public DegreeCentrality compute() {
41+
nodeQueue.set(0);
42+
final ArrayList<Future<?>> futures = new ArrayList<>();
43+
for (int i = 0; i < concurrency; i++) {
44+
futures.add(executor.submit(new DegreeTask()));
45+
}
46+
ParallelUtil.awaitTermination(futures);
47+
return this;
48+
}
49+
50+
@Override
51+
public DegreeCentrality me() {
52+
return this;
53+
}
54+
55+
@Override
56+
public DegreeCentrality release() {
57+
graph = null;
58+
return null;
59+
}
60+
61+
private class DegreeTask implements Runnable {
62+
@Override
63+
public void run() {
64+
for (; ; ) {
65+
final int nodeId = nodeQueue.getAndIncrement();
66+
if (nodeId >= nodeCount || !running()) {
67+
return;
68+
}
69+
70+
int degree = graph.degree(nodeId, direction);
71+
degrees[nodeId] = degree;
72+
73+
}
74+
}
75+
}
76+
77+
public int[] degrees() {
78+
return degrees;
79+
}
80+
81+
public Stream<Result> resultStream() {
82+
return IntStream.range(0, nodeCount)
83+
.mapToObj(nodeId ->
84+
new Result(graph.toOriginalNodeId(nodeId), degrees[nodeId]));
85+
}
86+
87+
/**
88+
* Result class used for streaming
89+
*/
90+
public static final class Result {
91+
92+
public final long nodeId;
93+
public final double centrality;
94+
95+
public Result(long nodeId, double centrality) {
96+
this.nodeId = nodeId;
97+
this.centrality = centrality;
98+
}
99+
100+
@Override
101+
public String toString() {
102+
return "Result{" +
103+
"nodeId=" + nodeId +
104+
", centrality=" + centrality +
105+
'}';
106+
}
107+
}
108+
109+
}
Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
package org.neo4j.graphalgo.impl;
2+
3+
import org.neo4j.graphalgo.api.Graph;
4+
import org.neo4j.graphalgo.api.WeightedRelationshipConsumer;
5+
import org.neo4j.graphalgo.core.utils.ParallelUtil;
6+
import org.neo4j.graphdb.Direction;
7+
8+
import java.util.ArrayList;
9+
import java.util.concurrent.ExecutorService;
10+
import java.util.concurrent.Future;
11+
import java.util.concurrent.atomic.AtomicInteger;
12+
import java.util.stream.IntStream;
13+
import java.util.stream.Stream;
14+
15+
public class WeightedDegreeCentrality extends Algorithm<WeightedDegreeCentrality> {
16+
private final int nodeCount;
17+
private Direction direction;
18+
private Graph graph;
19+
private final ExecutorService executor;
20+
private final int concurrency;
21+
private volatile AtomicInteger nodeQueue = new AtomicInteger();
22+
private int[] degrees;
23+
24+
public WeightedDegreeCentrality(
25+
Graph graph,
26+
ExecutorService executor,
27+
int concurrency,
28+
Direction direction
29+
) {
30+
31+
this.graph = graph;
32+
this.executor = executor;
33+
this.concurrency = concurrency;
34+
nodeCount = Math.toIntExact(graph.nodeCount());
35+
this.direction = direction;
36+
degrees = new int[nodeCount];
37+
}
38+
39+
public WeightedDegreeCentrality compute() {
40+
nodeQueue.set(0);
41+
final ArrayList<Future<?>> futures = new ArrayList<>();
42+
for (int i = 0; i < concurrency; i++) {
43+
futures.add(executor.submit(new DegreeTask()));
44+
}
45+
ParallelUtil.awaitTermination(futures);
46+
return this;
47+
}
48+
49+
@Override
50+
public WeightedDegreeCentrality me() {
51+
return this;
52+
}
53+
54+
@Override
55+
public WeightedDegreeCentrality release() {
56+
graph = null;
57+
return null;
58+
}
59+
60+
private class DegreeTask implements Runnable {
61+
@Override
62+
public void run() {
63+
for (; ; ) {
64+
final int nodeId = nodeQueue.getAndIncrement();
65+
if (nodeId >= nodeCount || !running()) {
66+
return;
67+
}
68+
69+
int[] weightedDegree = new int[1];
70+
graph.forEachRelationship(nodeId, direction, (sourceNodeId, targetNodeId, relationId, weight) -> {
71+
double v = graph.weightOf(targetNodeId, sourceNodeId);
72+
System.out.println(sourceNodeId + ", " + targetNodeId + " -> " + weight + ", " + v);
73+
weightedDegree[0] += weight;
74+
return true;
75+
});
76+
77+
degrees[nodeId] = weightedDegree[0];
78+
79+
}
80+
}
81+
}
82+
83+
public int[] degrees() {
84+
return degrees;
85+
}
86+
87+
public Stream<DegreeCentrality.Result> resultStream() {
88+
return IntStream.range(0, nodeCount)
89+
.mapToObj(nodeId ->
90+
new DegreeCentrality.Result(graph.toOriginalNodeId(nodeId), degrees[nodeId]));
91+
}
92+
93+
}

core/src/main/java/org/neo4j/graphalgo/core/neo4jview/GraphView.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -181,6 +181,10 @@ public int degree(int nodeId, Direction direction) {
181181
try (NodeCursor nc = transaction.cursors().allocateNodeCursor()) {
182182
transaction.dataRead().singleNode(toOriginalNodeId(nodeId), nc);
183183
if (nc.next()) {
184+
if (direction == Direction.BOTH || (direction == Direction.OUTGOING && loadAsUndirected) ) {
185+
return rels(transaction).degreeOf(Direction.BOTH, nc);
186+
}
187+
184188
return rels(transaction).degreeOf(direction, nc);
185189
}
186190
return 0;

0 commit comments

Comments
 (0)