Skip to content

Commit 3eed844

Browse files
committed
improve eksperimental Dijkstra by dropping unnecessary result store, layering responsibilities better, and generally simplifying
1 parent 72eeffa commit 3eed844

File tree

3 files changed

+56
-48
lines changed

3 files changed

+56
-48
lines changed

applications/algorithms/path-finding/src/main/java/org/neo4j/gds/applications/algorithms/pathfinding/PathFindingAlgorithmsMutateModeBusinessFacade.java

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,6 @@
2121

2222
import org.neo4j.gds.RelationshipType;
2323
import org.neo4j.gds.api.GraphName;
24-
import org.neo4j.gds.api.ResultStore;
25-
import org.neo4j.gds.api.nodeproperties.ValueType;
2624
import org.neo4j.gds.applications.algorithms.machinery.AlgorithmLabel;
2725
import org.neo4j.gds.applications.algorithms.machinery.AlgorithmProcessingTemplate;
2826
import org.neo4j.gds.applications.algorithms.machinery.AlgorithmProcessingTemplateConvenience;
@@ -53,8 +51,9 @@
5351
import org.neo4j.gds.steiner.SteinerTreeResult;
5452
import org.neo4j.gds.traversal.RandomWalkMutateConfig;
5553

56-
import java.util.List;
54+
import java.util.Map;
5755
import java.util.Optional;
56+
import java.util.stream.Stream;
5857

5958
import static org.neo4j.gds.applications.algorithms.machinery.AlgorithmLabel.AStar;
6059
import static org.neo4j.gds.applications.algorithms.machinery.AlgorithmLabel.BFS;
@@ -243,9 +242,10 @@ public <RESULT> RESULT singlePairShortestPathDijkstra(
243242
public <RESULT> RESULT singlePairShortestPathDijkstraWithPaths(
244243
GraphName graphName,
245244
ShortestPathDijkstraMutateConfig configuration,
246-
ResultStore resultStore,
245+
Map<String, Stream<PathUsingInternalNodeIds>> pathStore,
247246
ResultBuilder<ShortestPathDijkstraMutateConfig, PathFindingResult, RESULT, Void> resultBuilder
248247
) {
248+
var sideEffect = new StorePathsSideEffect(pathStore, configuration.mutateRelationshipType());
249249

250250
return algorithmProcessingTemplate.processAlgorithmAndAnySideEffects(
251251
Optional.empty(),
@@ -257,10 +257,9 @@ public <RESULT> RESULT singlePairShortestPathDijkstraWithPaths(
257257
DimensionTransformer.DISABLED,
258258
() -> estimationFacade.singlePairShortestPathDijkstra(configuration),
259259
(graph, __) -> pathFindingAlgorithms.singlePairShortestPathDijkstra(graph, configuration),
260-
Optional.of(new StorePathsSideEffect(resultStore, configuration.mutateRelationshipType(), List.of("totalCost", "nodeIds", "costs"), List.of(ValueType.DOUBLE, ValueType.LONG_ARRAY, ValueType.DOUBLE_ARRAY))),
260+
Optional.of(sideEffect),
261261
new MutateResultRenderer<>(configuration, resultBuilder)
262262
);
263-
264263
}
265264

266265
public <RESULT> RESULT singlePairShortestPathYens(
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
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.gds.applications.algorithms.pathfinding;
21+
22+
/**
23+
* Back in the day, this would be a DTO I guess
24+
*/
25+
public record PathUsingInternalNodeIds(long sourceNode, long targetNode, long[] nodeIds, double[] costs, double totalCost) {}

applications/algorithms/path-finding/src/main/java/org/neo4j/gds/applications/algorithms/pathfinding/StorePathsSideEffect.java

Lines changed: 26 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -19,70 +19,54 @@
1919
*/
2020
package org.neo4j.gds.applications.algorithms.pathfinding;
2121

22-
import org.neo4j.gds.api.ExportedRelationship;
23-
import org.neo4j.gds.api.ResultStore;
24-
import org.neo4j.gds.api.ResultStoreEntry;
25-
import org.neo4j.gds.api.nodeproperties.ValueType;
2622
import org.neo4j.gds.applications.algorithms.machinery.SideEffect;
2723
import org.neo4j.gds.core.loading.GraphResources;
28-
import org.neo4j.gds.core.utils.progress.JobId;
29-
import org.neo4j.gds.paths.PathResult;
3024
import org.neo4j.gds.paths.dijkstra.PathFindingResult;
31-
import org.neo4j.values.storable.Value;
32-
import org.neo4j.values.storable.Values;
3325

34-
import java.util.List;
26+
import java.util.Map;
3527
import java.util.Optional;
3628
import java.util.stream.Stream;
3729

38-
public class StorePathsSideEffect implements SideEffect<PathFindingResult, Void> {
39-
private final ResultStore resultStore;
30+
/**
31+
* This is our hook for storing Dijkstra paths in a place where they can later be found.
32+
* I.e. we stick them in a map, keyed by relationship type as a pseudo parameter.
33+
* The paths themselves are represented as internal node ids, costs of the hops between them, and the sum of the costs.
34+
* It is the responsibility of outer layers to map the internal node ids back into user space.
35+
*/
36+
class StorePathsSideEffect implements SideEffect<PathFindingResult, Void> {
37+
private final Map<String, Stream<PathUsingInternalNodeIds>> paths;
4038
private final String relationshipTypeAsString;
41-
private final List<String> propertyKeys;
42-
private final List<ValueType> propertyTypes;
4339

44-
public StorePathsSideEffect(
45-
ResultStore resultStore,
46-
String relationshipTypeAsString,
47-
List<String> propertyKeys,
48-
List<ValueType> propertyTypes
40+
StorePathsSideEffect(
41+
Map<String, Stream<PathUsingInternalNodeIds>> paths,
42+
String relationshipTypeAsString
4943
) {
50-
this.resultStore = resultStore;
44+
this.paths = paths;
5145
this.relationshipTypeAsString = relationshipTypeAsString;
52-
this.propertyKeys = propertyKeys;
53-
this.propertyTypes = propertyTypes;
5446
}
5547

5648
@Override
5749
public Optional<Void> process(GraphResources graphResources, Optional<PathFindingResult> pathFindingResult) {
5850
if (pathFindingResult.isEmpty()) {
5951
return Optional.empty();
6052
}
61-
var actualPathResult = pathFindingResult.get();
62-
Stream<ExportedRelationship> relationshipStream = actualPathResult.mapPaths(
63-
pathResult -> new ExportedRelationship(
53+
54+
var actualPathResult = pathFindingResult.get();
55+
56+
// just record the paths, no conversions, that happens later
57+
var pathStream = actualPathResult.mapPaths(
58+
pathResult -> new PathUsingInternalNodeIds(
6459
pathResult.sourceNode(),
6560
pathResult.targetNode(),
66-
createValues(pathResult)
67-
));
68-
69-
ResultStoreEntry.RelationshipStream streamEntry = new ResultStoreEntry.RelationshipStream(
70-
relationshipTypeAsString,
71-
propertyKeys,
72-
propertyTypes,
73-
relationshipStream,
74-
graphResources.graph()::toOriginalNodeId
61+
pathResult.nodeIds(),
62+
pathResult.costs(),
63+
pathResult.totalCost()
64+
)
7565
);
76-
resultStore.add(JobId.parse(this.relationshipTypeAsString), streamEntry);
7766

78-
return Optional.empty();
79-
}
67+
paths.put(relationshipTypeAsString, pathStream);
8068

81-
private Value[] createValues(PathResult pathResult) {
82-
return new Value[]{
83-
Values.doubleValue(pathResult.totalCost()),
84-
Values.longArray(pathResult.nodeIds()),
85-
Values.doubleArray(pathResult.costs())
86-
};
69+
// we have no interesting metadata
70+
return Optional.empty();
8771
}
8872
}

0 commit comments

Comments
 (0)