Skip to content

Commit 9d32db7

Browse files
Remove write columns from NodeSim stats result
We've already split NodeSim stats proc and config out. There is no reason for it to use the `write()` method or the `WriteResult` from the write mode proc anymore. Co-Authored-By: Jacob Sznajdman <breakanalysis@gmail.com>
1 parent 1fb6b9f commit 9d32db7

File tree

4 files changed

+308
-183
lines changed

4 files changed

+308
-183
lines changed

proc/src/main/java/org/neo4j/graphalgo/nodesim/NodeSimilarityBaseProc.java

Lines changed: 1 addition & 179 deletions
Original file line numberDiff line numberDiff line change
@@ -23,17 +23,10 @@
2323
import org.neo4j.graphalgo.AlgoBaseProc;
2424
import org.neo4j.graphalgo.AlgorithmFactory;
2525
import org.neo4j.graphalgo.api.Graph;
26-
import org.neo4j.graphalgo.compat.MapUtil;
2726
import org.neo4j.graphalgo.core.CypherMapWrapper;
28-
import org.neo4j.graphalgo.core.utils.ProgressTimer;
29-
import org.neo4j.graphalgo.core.write.RelationshipExporter;
3027
import org.neo4j.graphalgo.newapi.GraphCreateConfig;
31-
import org.neo4j.graphalgo.result.AbstractResultBuilder;
3228

33-
import java.util.Collections;
34-
import java.util.Map;
3529
import java.util.Optional;
36-
import java.util.stream.Stream;
3730

3831
public abstract class NodeSimilarityBaseProc<CONFIG extends NodeSimilarityBaseConfig> extends AlgoBaseProc<NodeSimilarity, NodeSimilarityResult, CONFIG> {
3932

@@ -54,82 +47,7 @@ protected AlgorithmFactory<NodeSimilarity, CONFIG> algorithmFactory(CONFIG confi
5447
return new NodeSimilarityFactory<>();
5548
}
5649

57-
public Stream<WriteResult> write(
58-
ComputationResult<NodeSimilarity, NodeSimilarityResult, CONFIG> computationResult
59-
) {
60-
CONFIG config = computationResult.config();
61-
62-
if (computationResult.isGraphEmpty()) {
63-
return Stream.of(
64-
new WriteResult(
65-
computationResult.createMillis(),
66-
0,
67-
0,
68-
0,
69-
0,
70-
0,
71-
Collections.emptyMap(),
72-
config.toMap()
73-
)
74-
);
75-
}
76-
77-
NodeSimilarityResult result = computationResult.result();
78-
NodeSimilarity algorithm = computationResult.algorithm();
79-
SimilarityGraphResult similarityGraphResult = result.maybeGraphResult().get();
80-
Graph similarityGraph = similarityGraphResult.similarityGraph();
81-
82-
WriteResultBuilder resultBuilder = new WriteResultBuilder();
83-
resultBuilder
84-
.withNodesCompared(similarityGraphResult.comparedNodes())
85-
.withRelationshipsWritten(similarityGraphResult.similarityGraph().relationshipCount());
86-
resultBuilder.withCreateMillis(computationResult.createMillis());
87-
resultBuilder.withComputeMillis(computationResult.computeMillis());
88-
resultBuilder.withConfig(config);
89-
90-
boolean shouldComputeHistogram = callContext
91-
.outputFields()
92-
.anyMatch(s -> s.equalsIgnoreCase("similarityDistribution"));
93-
if (shouldWrite(config) && similarityGraph.relationshipCount() > 0) {
94-
NodeSimilarityWriteConfig writeConfig = (NodeSimilarityWriteConfig) config;
95-
96-
String writeRelationshipType = writeConfig.writeRelationshipType();
97-
String writeProperty = writeConfig.writeProperty();
98-
99-
runWithExceptionLogging(
100-
"NodeSimilarity write-back failed",
101-
() -> {
102-
try (ProgressTimer ignored = ProgressTimer.start(resultBuilder::withWriteMillis)) {
103-
RelationshipExporter exporter = RelationshipExporter
104-
.of(api, similarityGraph, algorithm.getTerminationFlag())
105-
.withLog(log)
106-
.build();
107-
if (shouldComputeHistogram) {
108-
DoubleHistogram histogram = new DoubleHistogram(5);
109-
exporter.write(
110-
writeRelationshipType,
111-
writeProperty,
112-
(node1, node2, similarity) -> {
113-
histogram.recordValue(similarity);
114-
return true;
115-
}
116-
);
117-
resultBuilder.withHistogram(histogram);
118-
} else {
119-
exporter.write(writeRelationshipType, writeProperty);
120-
}
121-
}
122-
}
123-
);
124-
} else if (shouldComputeHistogram) {
125-
try (ProgressTimer ignored = resultBuilder.timePostProcessing()) {
126-
resultBuilder.withHistogram(computeHistogram(similarityGraph));
127-
}
128-
}
129-
return Stream.of(resultBuilder.build());
130-
}
131-
132-
private DoubleHistogram computeHistogram(Graph similarityGraph) {
50+
DoubleHistogram computeHistogram(Graph similarityGraph) {
13351
DoubleHistogram histogram = new DoubleHistogram(5);
13452
similarityGraph.forEachNode(nodeId -> {
13553
similarityGraph.forEachRelationship(nodeId, Double.NaN, (node1, node2, property) -> {
@@ -141,100 +59,4 @@ private DoubleHistogram computeHistogram(Graph similarityGraph) {
14159
return histogram;
14260
}
14361

144-
public static class WriteResult {
145-
public final long loadMillis;
146-
public final long computeMillis;
147-
public final long writeMillis;
148-
public final long postProcessingMillis;
149-
150-
public final long nodesCompared;
151-
public final long relationshipsWritten;
152-
153-
public final Map<String, Object> similarityDistribution;
154-
public final Map<String, Object> configuration;
155-
156-
WriteResult(
157-
long loadMillis,
158-
long computeMillis,
159-
long writeMillis,
160-
long postProcessingMillis,
161-
long nodesCompared,
162-
long relationshipsWritten,
163-
Map<String, Object> similarityDistribution,
164-
Map<String, Object> configuration
165-
) {
166-
this.loadMillis = loadMillis;
167-
this.computeMillis = computeMillis;
168-
this.writeMillis = writeMillis;
169-
this.postProcessingMillis = postProcessingMillis;
170-
this.nodesCompared = nodesCompared;
171-
this.relationshipsWritten = relationshipsWritten;
172-
this.similarityDistribution = similarityDistribution;
173-
this.configuration = configuration;
174-
}
175-
}
176-
177-
static class WriteResultBuilder extends AbstractResultBuilder<WriteResult> {
178-
179-
private long nodesCompared = 0L;
180-
181-
private long postProcessingMillis = -1L;
182-
183-
private Optional<DoubleHistogram> maybeHistogram = Optional.empty();
184-
185-
public WriteResultBuilder withNodesCompared(long nodesCompared) {
186-
this.nodesCompared = nodesCompared;
187-
return this;
188-
}
189-
190-
WriteResultBuilder withHistogram(DoubleHistogram histogram) {
191-
this.maybeHistogram = Optional.of(histogram);
192-
return this;
193-
}
194-
195-
void setPostProcessingMillis(long postProcessingMillis) {
196-
this.postProcessingMillis = postProcessingMillis;
197-
}
198-
199-
ProgressTimer timePostProcessing() {
200-
return ProgressTimer.start(this::setPostProcessingMillis);
201-
}
202-
203-
private Map<String, Object> distribution() {
204-
if (maybeHistogram.isPresent()) {
205-
DoubleHistogram definitelyHistogram = maybeHistogram.get();
206-
return MapUtil.map(
207-
"min", definitelyHistogram.getMinValue(),
208-
"max", definitelyHistogram.getMaxValue(),
209-
"mean", definitelyHistogram.getMean(),
210-
"stdDev", definitelyHistogram.getStdDeviation(),
211-
"p1", definitelyHistogram.getValueAtPercentile(1),
212-
"p5", definitelyHistogram.getValueAtPercentile(5),
213-
"p10", definitelyHistogram.getValueAtPercentile(10),
214-
"p25", definitelyHistogram.getValueAtPercentile(25),
215-
"p50", definitelyHistogram.getValueAtPercentile(50),
216-
"p75", definitelyHistogram.getValueAtPercentile(75),
217-
"p90", definitelyHistogram.getValueAtPercentile(90),
218-
"p95", definitelyHistogram.getValueAtPercentile(95),
219-
"p99", definitelyHistogram.getValueAtPercentile(99),
220-
"p100", definitelyHistogram.getValueAtPercentile(100)
221-
);
222-
}
223-
return Collections.emptyMap();
224-
}
225-
226-
@Override
227-
public WriteResult build() {
228-
return new WriteResult(
229-
createMillis,
230-
computeMillis,
231-
writeMillis,
232-
postProcessingMillis,
233-
nodesCompared,
234-
relationshipsWritten,
235-
distribution(),
236-
config.toMap()
237-
);
238-
}
239-
}
24062
}

proc/src/main/java/org/neo4j/graphalgo/nodesim/NodeSimilarityStatsProc.java

Lines changed: 137 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,15 +19,21 @@
1919
*/
2020
package org.neo4j.graphalgo.nodesim;
2121

22+
import org.HdrHistogram.DoubleHistogram;
2223
import org.neo4j.graphalgo.AlgoBaseProc;
24+
import org.neo4j.graphalgo.api.Graph;
25+
import org.neo4j.graphalgo.compat.MapUtil;
2326
import org.neo4j.graphalgo.core.CypherMapWrapper;
27+
import org.neo4j.graphalgo.core.utils.ProgressTimer;
2428
import org.neo4j.graphalgo.newapi.GraphCreateConfig;
29+
import org.neo4j.graphalgo.result.AbstractResultBuilder;
2530
import org.neo4j.graphalgo.results.MemoryEstimateResult;
2631
import org.neo4j.procedure.Description;
2732
import org.neo4j.procedure.Mode;
2833
import org.neo4j.procedure.Name;
2934
import org.neo4j.procedure.Procedure;
3035

36+
import java.util.Collections;
3137
import java.util.Map;
3238
import java.util.Optional;
3339
import java.util.stream.Stream;
@@ -38,15 +44,15 @@ public class NodeSimilarityStatsProc extends NodeSimilarityBaseProc<NodeSimilari
3844

3945
@Procedure(name = "gds.nodeSimilarity.stats", mode = Mode.WRITE)
4046
@Description(STATS_DESCRIPTION)
41-
public Stream<NodeSimilarityBaseProc.WriteResult> stats(
47+
public Stream<StatsResult> stats(
4248
@Name(value = "graphName") Object graphNameOrConfig,
4349
@Name(value = "configuration", defaultValue = "{}") Map<String, Object> configuration
4450
) {
4551
AlgoBaseProc.ComputationResult<NodeSimilarity, NodeSimilarityResult, NodeSimilarityStatsConfig> result = compute(
4652
graphNameOrConfig,
4753
configuration
4854
);
49-
return write(result);
55+
return stats(result);
5056
}
5157

5258
@Procedure(value = "gds.nodeSimilarity.stats.estimate", mode = READ)
@@ -67,4 +73,133 @@ protected NodeSimilarityStatsConfig newConfig(
6773
) {
6874
return NodeSimilarityStatsConfig.of(username, graphName, maybeImplicitCreate, config);
6975
}
76+
77+
public Stream<StatsResult> stats(ComputationResult<NodeSimilarity, NodeSimilarityResult, NodeSimilarityStatsConfig> computationResult) {
78+
NodeSimilarityStatsConfig config = computationResult.config();
79+
80+
if (computationResult.isGraphEmpty()) {
81+
return Stream.of(
82+
new StatsResult(
83+
computationResult.createMillis(),
84+
0,
85+
0,
86+
0,
87+
Collections.emptyMap(),
88+
config.toMap()
89+
)
90+
);
91+
}
92+
93+
NodeSimilarityResult result = computationResult.result();
94+
SimilarityGraphResult similarityGraphResult = result.maybeGraphResult().get();
95+
Graph similarityGraph = similarityGraphResult.similarityGraph();
96+
97+
StatsResultBuilder resultBuilder = new StatsResultBuilder();
98+
resultBuilder
99+
.withNodesCompared(similarityGraphResult.comparedNodes())
100+
.withRelationshipsWritten(similarityGraph.relationshipCount());
101+
resultBuilder.withCreateMillis(computationResult.createMillis());
102+
resultBuilder.withComputeMillis(computationResult.computeMillis());
103+
resultBuilder.withConfig(config);
104+
105+
boolean shouldComputeHistogram = callContext
106+
.outputFields()
107+
.anyMatch(s -> s.equalsIgnoreCase("similarityDistribution"));
108+
if (shouldComputeHistogram) {
109+
try (ProgressTimer ignored = resultBuilder.timePostProcessing()) {
110+
resultBuilder.withHistogram(computeHistogram(similarityGraph));
111+
}
112+
}
113+
return Stream.of(resultBuilder.build());
114+
}
115+
116+
117+
public static final class StatsResult {
118+
119+
public long createMillis;
120+
public long computeMillis;
121+
public long postProcessingMillis;
122+
public long nodesCompared;
123+
public Map<String, Object> similarityDistribution;
124+
public Map<String, Object> configuration;
125+
126+
StatsResult(
127+
long createMillis,
128+
long computeMillis,
129+
long postProcessingMillis,
130+
long nodesCompared,
131+
Map<String, Object> communityDistribution,
132+
Map<String, Object> configuration
133+
134+
) {
135+
this.createMillis = createMillis;
136+
this.computeMillis = computeMillis;
137+
this.postProcessingMillis = postProcessingMillis;
138+
this.nodesCompared = nodesCompared;
139+
this.similarityDistribution = communityDistribution;
140+
this.configuration = configuration;
141+
}
142+
}
143+
144+
static class StatsResultBuilder extends AbstractResultBuilder<StatsResult> {
145+
146+
private long nodesCompared = 0L;
147+
148+
private long postProcessingMillis = -1L;
149+
150+
private Optional<DoubleHistogram> maybeHistogram = Optional.empty();
151+
152+
public StatsResultBuilder withNodesCompared(long nodesCompared) {
153+
this.nodesCompared = nodesCompared;
154+
return this;
155+
}
156+
157+
StatsResultBuilder withHistogram(DoubleHistogram histogram) {
158+
this.maybeHistogram = Optional.of(histogram);
159+
return this;
160+
}
161+
162+
void setPostProcessingMillis(long postProcessingMillis) {
163+
this.postProcessingMillis = postProcessingMillis;
164+
}
165+
166+
ProgressTimer timePostProcessing() {
167+
return ProgressTimer.start(this::setPostProcessingMillis);
168+
}
169+
170+
private Map<String, Object> distribution() {
171+
if (maybeHistogram.isPresent()) {
172+
DoubleHistogram definitelyHistogram = maybeHistogram.get();
173+
return MapUtil.map(
174+
"min", definitelyHistogram.getMinValue(),
175+
"max", definitelyHistogram.getMaxValue(),
176+
"mean", definitelyHistogram.getMean(),
177+
"stdDev", definitelyHistogram.getStdDeviation(),
178+
"p1", definitelyHistogram.getValueAtPercentile(1),
179+
"p5", definitelyHistogram.getValueAtPercentile(5),
180+
"p10", definitelyHistogram.getValueAtPercentile(10),
181+
"p25", definitelyHistogram.getValueAtPercentile(25),
182+
"p50", definitelyHistogram.getValueAtPercentile(50),
183+
"p75", definitelyHistogram.getValueAtPercentile(75),
184+
"p90", definitelyHistogram.getValueAtPercentile(90),
185+
"p95", definitelyHistogram.getValueAtPercentile(95),
186+
"p99", definitelyHistogram.getValueAtPercentile(99),
187+
"p100", definitelyHistogram.getValueAtPercentile(100)
188+
);
189+
}
190+
return Collections.emptyMap();
191+
}
192+
193+
@Override
194+
public StatsResult build() {
195+
return new StatsResult(
196+
createMillis,
197+
computeMillis,
198+
postProcessingMillis,
199+
nodesCompared,
200+
distribution(),
201+
config.toMap()
202+
);
203+
}
204+
}
70205
}

0 commit comments

Comments
 (0)