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

Commit 528e9da

Browse files
mknblchmneedham
authored andcommitted
Danglachev centrality (#549)
* WIP * add testcase for 546 * cleanup * meant 547 * WIP * WIP * add proc + test * revert changes in HCC * revert unwanted changes
1 parent e66d76e commit 528e9da

File tree

5 files changed

+606
-0
lines changed

5 files changed

+606
-0
lines changed
Lines changed: 141 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,141 @@
1+
/**
2+
* Copyright (c) 2017 "Neo4j, Inc." <http://neo4j.com>
3+
*
4+
* This file is part of Neo4j Graph Algorithms <http://github.com/neo4j-contrib/neo4j-graph-algorithms>.
5+
*
6+
* Neo4j Graph Algorithms is free software: you can redistribute it and/or modify
7+
* it under the terms of the GNU General Public License as published by
8+
* the Free Software Foundation, either version 3 of the License, or
9+
* (at your option) any later version.
10+
*
11+
* This program is distributed in the hope that it will be useful,
12+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
13+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14+
* GNU General Public License for more details.
15+
*
16+
* You should have received a copy of the GNU General Public License
17+
* along with this program. If not, see <http://www.gnu.org/licenses/>.
18+
*/
19+
package org.neo4j.graphalgo;
20+
21+
import org.neo4j.graphalgo.api.Graph;
22+
import org.neo4j.graphalgo.core.GraphLoader;
23+
import org.neo4j.graphalgo.core.ProcedureConfiguration;
24+
import org.neo4j.graphalgo.core.utils.Pools;
25+
import org.neo4j.graphalgo.core.utils.ProgressLogger;
26+
import org.neo4j.graphalgo.core.utils.ProgressTimer;
27+
import org.neo4j.graphalgo.core.utils.TerminationFlag;
28+
import org.neo4j.graphalgo.core.utils.paged.AllocationTracker;
29+
import org.neo4j.graphalgo.core.write.Exporter;
30+
import org.neo4j.graphalgo.impl.harmonic.HarmonicCentrality;
31+
import org.neo4j.graphalgo.impl.DangalchevClosenessCentrality;
32+
import org.neo4j.graphalgo.results.CentralityProcResult;
33+
import org.neo4j.graphdb.Direction;
34+
import org.neo4j.kernel.api.KernelTransaction;
35+
import org.neo4j.kernel.internal.GraphDatabaseAPI;
36+
import org.neo4j.logging.Log;
37+
import org.neo4j.procedure.*;
38+
39+
import java.util.Map;
40+
import java.util.stream.Stream;
41+
42+
/**
43+
* @author mknblch
44+
*/
45+
public class DangalchevCentralityProc {
46+
47+
public static final String DEFAULT_TARGET_PROPERTY = "centrality";
48+
49+
@Context
50+
public GraphDatabaseAPI api;
51+
52+
@Context
53+
public Log log;
54+
55+
@Context
56+
public KernelTransaction transaction;
57+
58+
@Procedure(value = "algo.dangalchev.stream")
59+
@Description("CALL algo.dangalchev.stream(label:String, relationship:String{concurrency:4}) YIELD nodeId, centrality - yields centrality for each node")
60+
public Stream<DangalchevClosenessCentrality.Result> dangalchevStream(
61+
@Name(value = "label", defaultValue = "") String label,
62+
@Name(value = "relationship", defaultValue = "") String relationship,
63+
@Name(value = "config", defaultValue = "{}") Map<String, Object> config) {
64+
65+
final ProcedureConfiguration configuration = ProcedureConfiguration.create(config)
66+
.overrideNodeLabelOrQuery(label)
67+
.overrideRelationshipTypeOrQuery(relationship);
68+
69+
final AllocationTracker tracker = AllocationTracker.create();
70+
71+
final Graph graph = new GraphLoader(api, Pools.DEFAULT)
72+
.init(log, configuration.getNodeLabelOrQuery(), configuration.getRelationshipOrQuery(), configuration)
73+
.withoutNodeProperties()
74+
.withConcurrency(configuration.getConcurrency())
75+
.withAllocationTracker(tracker)
76+
.asUndirected(true)
77+
.load(configuration.getGraphImpl("huge"));
78+
79+
final DangalchevClosenessCentrality algo = new DangalchevClosenessCentrality(graph, configuration.getConcurrency(), Pools.DEFAULT)
80+
.withProgressLogger(ProgressLogger.wrap(log, "DangalchevCentrality"))
81+
.withTerminationFlag(TerminationFlag.wrap(transaction))
82+
.compute();
83+
84+
graph.release();
85+
86+
return algo.resultStream();
87+
}
88+
89+
@Procedure(value = "algo.dangalchev", mode = Mode.WRITE)
90+
@Description("CALL algo.dangalchev(label:String, relationship:String, {write:true, writeProperty:'centrality, concurrency:4'}) YIELD " +
91+
"loadMillis, computeMillis, writeMillis, nodes] - yields evaluation details")
92+
public Stream<CentralityProcResult> dangalchev(
93+
@Name(value = "label", defaultValue = "") String label,
94+
@Name(value = "relationship", defaultValue = "") String relationship,
95+
@Name(value = "config", defaultValue = "{}") Map<String, Object> config) {
96+
97+
final ProcedureConfiguration configuration = ProcedureConfiguration.create(config)
98+
.overrideNodeLabelOrQuery(label)
99+
.overrideRelationshipTypeOrQuery(relationship);
100+
101+
final CentralityProcResult.Builder builder = CentralityProcResult.builder();
102+
103+
final AllocationTracker tracker = AllocationTracker.create();
104+
final int concurrency = configuration.getConcurrency();
105+
final TerminationFlag terminationFlag = TerminationFlag.wrap(transaction);
106+
107+
final Graph graph;
108+
try (ProgressTimer timer = builder.timeLoad()) {
109+
graph = new GraphLoader(api, Pools.DEFAULT)
110+
.init(log, configuration.getNodeLabelOrQuery(), configuration.getRelationshipOrQuery(), configuration)
111+
.withoutNodeProperties()
112+
.withConcurrency(concurrency)
113+
.withAllocationTracker(tracker)
114+
.asUndirected(true)
115+
.load(configuration.getGraphImpl("huge"));
116+
}
117+
118+
builder.withNodeCount(graph.nodeCount());
119+
120+
final DangalchevClosenessCentrality algo = new DangalchevClosenessCentrality(graph, concurrency, Pools.DEFAULT)
121+
.withProgressLogger(ProgressLogger.wrap(log, "DangalchevCentrality"))
122+
.withTerminationFlag(TerminationFlag.wrap(transaction));
123+
124+
builder.timeEval(algo::compute);
125+
126+
if (configuration.isWriteFlag()) {
127+
graph.release();
128+
final String writeProperty = configuration.getWriteProperty(DEFAULT_TARGET_PROPERTY);
129+
builder.timeWrite(() -> {
130+
Exporter exporter = Exporter.of(api, graph)
131+
.withLog(log)
132+
.parallel(Pools.DEFAULT, concurrency, terminationFlag)
133+
.build();
134+
algo.export(writeProperty, exporter);
135+
});
136+
algo.release();
137+
}
138+
139+
return Stream.of(builder.build());
140+
}
141+
}
Lines changed: 114 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,114 @@
1+
/**
2+
* Copyright (c) 2017 "Neo4j, Inc." <http://neo4j.com>
3+
*
4+
* This file is part of Neo4j Graph Algorithms <http://github.com/neo4j-contrib/neo4j-graph-algorithms>.
5+
*
6+
* Neo4j Graph Algorithms is free software: you can redistribute it and/or modify
7+
* it under the terms of the GNU General Public License as published by
8+
* the Free Software Foundation, either version 3 of the License, or
9+
* (at your option) any later version.
10+
*
11+
* This program is distributed in the hope that it will be useful,
12+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
13+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14+
* GNU General Public License for more details.
15+
*
16+
* You should have received a copy of the GNU General Public License
17+
* along with this program. If not, see <http://www.gnu.org/licenses/>.
18+
*/
19+
package org.neo4j.graphalgo.impl;
20+
21+
import org.neo4j.graphalgo.api.Graph;
22+
import org.neo4j.graphalgo.core.utils.AtomicDoubleArray;
23+
import org.neo4j.graphalgo.core.utils.ProgressLogger;
24+
import org.neo4j.graphalgo.core.write.Exporter;
25+
import org.neo4j.graphalgo.core.write.PropertyTranslator;
26+
import org.neo4j.graphalgo.impl.msbfs.BfsConsumer;
27+
import org.neo4j.graphalgo.impl.msbfs.MultiSourceBFS;
28+
import org.neo4j.graphdb.Direction;
29+
30+
import java.util.concurrent.ExecutorService;
31+
import java.util.stream.IntStream;
32+
import java.util.stream.Stream;
33+
34+
/**
35+
* Dangalchev Closeness Centrality
36+
*
37+
* @author mknblch
38+
*/
39+
public class DangalchevClosenessCentrality extends Algorithm<DangalchevClosenessCentrality> {
40+
41+
private Graph graph;
42+
private AtomicDoubleArray farness;
43+
44+
private final int concurrency;
45+
private final ExecutorService executorService;
46+
private final int nodeCount;
47+
48+
public DangalchevClosenessCentrality(Graph graph, int concurrency, ExecutorService executorService) {
49+
this.graph = graph;
50+
nodeCount = Math.toIntExact(graph.nodeCount());
51+
this.concurrency = concurrency;
52+
this.executorService = executorService;
53+
farness = new AtomicDoubleArray(nodeCount);
54+
}
55+
56+
public DangalchevClosenessCentrality compute() {
57+
58+
final ProgressLogger progressLogger = getProgressLogger();
59+
60+
final BfsConsumer consumer = (nodeId, depth, sourceNodeIds) -> {
61+
int len = sourceNodeIds.size();
62+
farness.add(nodeId, len * 1.0 / Math.pow(2, depth));
63+
progressLogger.logProgress((double) nodeId / (nodeCount - 1));
64+
};
65+
66+
new MultiSourceBFS(graph, graph, Direction.OUTGOING, consumer)
67+
.run(concurrency, executorService);
68+
69+
return this;
70+
}
71+
72+
public Stream<Result> resultStream() {
73+
return IntStream.range(0, nodeCount)
74+
.mapToObj(nodeId -> new Result(
75+
graph.toOriginalNodeId(nodeId),
76+
farness.get(nodeId)));
77+
}
78+
79+
public void export(final String propertyName, final Exporter exporter) {
80+
exporter.write(
81+
propertyName,
82+
farness,
83+
(PropertyTranslator.OfDouble<AtomicDoubleArray>)
84+
(data, nodeId) -> data.get((int) nodeId));
85+
}
86+
87+
@Override
88+
public DangalchevClosenessCentrality me() {
89+
return this;
90+
}
91+
92+
@Override
93+
public DangalchevClosenessCentrality release() {
94+
graph = null;
95+
farness = null;
96+
return this;
97+
}
98+
99+
100+
/**
101+
* Result class used for streaming
102+
*/
103+
public static final class Result {
104+
105+
public final long nodeId;
106+
107+
public final double centrality;
108+
109+
public Result(long nodeId, double centrality) {
110+
this.nodeId = nodeId;
111+
this.centrality = centrality;
112+
}
113+
}
114+
}

algo/src/main/java/org/neo4j/graphalgo/impl/MSClosenessCentrality.java

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -120,5 +120,13 @@ public Result(long nodeId, double centrality) {
120120
this.nodeId = nodeId;
121121
this.centrality = centrality;
122122
}
123+
124+
@Override
125+
public String toString() {
126+
return "Result{" +
127+
"nodeId=" + nodeId +
128+
", centrality=" + centrality +
129+
'}';
130+
}
123131
}
124132
}

0 commit comments

Comments
 (0)