Skip to content

Commit c4284ab

Browse files
committed
Implement NodeEmbeddingComputeBusinessFacade
1 parent b15ead3 commit c4284ab

File tree

4 files changed

+277
-1
lines changed

4 files changed

+277
-1
lines changed

algorithms-compute-business-facade/build.gradle

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,13 +6,14 @@ group = 'org.neo4j.gds'
66

77
dependencies {
88

9-
implementation project(':algo') // TODO: extract the results to a separate module and depend on it
9+
implementation project(':algo') // TODO: extract the results and config-parameter converters to a separate module and depend on it
1010
implementation project(':algo-common') // TODO: extract the results to a separate module and depend on it
1111
implementation project(':algorithms-compute-facade')
1212
implementation project(':collections')
1313
implementation project(':core') // TODO: this is here because of the `GraphStoreCatalogService` --> refactor it so we can use the service without bringing the entire sub-project
1414
implementation project(':graph-schema-api')
1515
implementation project(':logging')
16+
implementation project(':node-embeddings-params')
1617
implementation project(':path-finding-params')
1718
implementation project(':progress-tracking')
1819
implementation project(':string-formatting')
Lines changed: 156 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,156 @@
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.embeddings;
21+
22+
import org.neo4j.gds.GraphParameters;
23+
import org.neo4j.gds.api.DatabaseId;
24+
import org.neo4j.gds.api.GraphName;
25+
import org.neo4j.gds.api.User;
26+
import org.neo4j.gds.core.loading.GraphStoreCatalogService;
27+
import org.neo4j.gds.core.loading.validation.NoAlgorithmValidation;
28+
import org.neo4j.gds.core.utils.progress.JobId;
29+
import org.neo4j.gds.embeddings.fastrp.FastRPParameters;
30+
import org.neo4j.gds.embeddings.fastrp.FastRPResult;
31+
import org.neo4j.gds.embeddings.hashgnn.HashGNNParameters;
32+
import org.neo4j.gds.embeddings.hashgnn.HashGNNResult;
33+
import org.neo4j.gds.embeddings.node2vec.Node2VecParameters;
34+
import org.neo4j.gds.embeddings.node2vec.Node2VecResult;
35+
import org.neo4j.gds.embeddings.validation.FeaturePropertiesMustExistOnAllNodeLabels;
36+
import org.neo4j.gds.embeddings.validation.Node2VecGraphValidation;
37+
import org.neo4j.gds.result.TimedAlgorithmResult;
38+
import org.neo4j.gds.results.ResultTransformerBuilder;
39+
40+
import java.util.List;
41+
import java.util.Optional;
42+
import java.util.concurrent.CompletableFuture;
43+
44+
public class NodeEmbeddingComputeBusinessFacade {
45+
46+
// Global dependencies
47+
private final GraphStoreCatalogService graphStoreCatalogService;
48+
private final NodeEmbeddingComputeFacade computeFacade;
49+
50+
// Request scope dependencies
51+
private final User user;
52+
private final DatabaseId databaseId;
53+
54+
public NodeEmbeddingComputeBusinessFacade(
55+
GraphStoreCatalogService graphStoreCatalogService,
56+
NodeEmbeddingComputeFacade computeFacade,
57+
User user,
58+
DatabaseId databaseId
59+
) {
60+
this.graphStoreCatalogService = graphStoreCatalogService;
61+
this.computeFacade = computeFacade;
62+
this.user = user;
63+
this.databaseId = databaseId;
64+
}
65+
66+
public <TR> CompletableFuture<TR> fastRP(
67+
GraphName graphName,
68+
GraphParameters graphParameters,
69+
Optional<String> relationshipProperty,
70+
FastRPParameters parameters,
71+
JobId jobId,
72+
boolean logProgress,
73+
ResultTransformerBuilder<TimedAlgorithmResult<FastRPResult>, TR> resultTransformerBuilder
74+
) {
75+
76+
// Fetch the Graph the algorithm will operate on
77+
var graphResources = graphStoreCatalogService.fetchGraphResources(
78+
graphName,
79+
graphParameters,
80+
relationshipProperty,
81+
new FeaturePropertiesMustExistOnAllNodeLabels(parameters.featureProperties()),
82+
Optional.empty(),
83+
user,
84+
databaseId
85+
);
86+
87+
return computeFacade.fastRP(
88+
graphResources.graph(),
89+
parameters,
90+
jobId,
91+
logProgress
92+
).thenApply(resultTransformerBuilder.build(graphResources));
93+
}
94+
95+
public <TR> CompletableFuture<TR> hashGnn(
96+
GraphName graphName,
97+
GraphParameters graphParameters,
98+
// FIXME: `relationshipTypes` is only used to create progress tracker tasks, and in there only the count...
99+
List<String> relationshipTypes,
100+
Optional<String> relationshipProperty,
101+
HashGNNParameters parameters,
102+
JobId jobId,
103+
boolean logProgress,
104+
ResultTransformerBuilder<TimedAlgorithmResult<HashGNNResult>, TR> resultTransformerBuilder
105+
) {
106+
// Fetch the Graph the algorithm will operate on
107+
var graphResources = graphStoreCatalogService.fetchGraphResources(
108+
graphName,
109+
graphParameters,
110+
relationshipProperty,
111+
new FeaturePropertiesMustExistOnAllNodeLabels(parameters.featureProperties()),
112+
Optional.empty(),
113+
user,
114+
databaseId
115+
);
116+
117+
return computeFacade.hashGnn(
118+
graphResources.graph(),
119+
parameters,
120+
relationshipTypes,
121+
jobId,
122+
logProgress
123+
).thenApply(resultTransformerBuilder.build(graphResources));
124+
}
125+
126+
public <TR> CompletableFuture<TR> node2Vec(
127+
GraphName graphName,
128+
GraphParameters graphParameters,
129+
Optional<String> relationshipProperty,
130+
Node2VecParameters parameters,
131+
JobId jobId,
132+
boolean logProgress,
133+
ResultTransformerBuilder<TimedAlgorithmResult<Node2VecResult>, TR> resultTransformerBuilder
134+
) {
135+
// Fetch the Graph the algorithm will operate on
136+
var graphResources = graphStoreCatalogService.fetchGraphResources(
137+
graphName,
138+
graphParameters,
139+
relationshipProperty,
140+
new NoAlgorithmValidation(),
141+
Optional.of(new Node2VecGraphValidation(
142+
parameters.samplingWalkParameters().walksPerNode(),
143+
parameters.samplingWalkParameters().walkLength()
144+
)),
145+
user,
146+
databaseId
147+
);
148+
149+
return computeFacade.node2Vec(
150+
graphResources.graph(),
151+
parameters,
152+
jobId,
153+
logProgress
154+
).thenApply(resultTransformerBuilder.build(graphResources));
155+
}
156+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
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.embeddings.validation;
21+
22+
import org.neo4j.gds.NodeLabel;
23+
import org.neo4j.gds.RelationshipType;
24+
import org.neo4j.gds.api.GraphStore;
25+
import org.neo4j.gds.core.loading.validation.GraphStoreValidation;
26+
import org.neo4j.gds.utils.StringJoining;
27+
28+
import java.util.Collection;
29+
import java.util.List;
30+
import java.util.stream.Collectors;
31+
32+
import static org.neo4j.gds.utils.StringFormatting.formatWithLocale;
33+
34+
public class FeaturePropertiesMustExistOnAllNodeLabels extends GraphStoreValidation {
35+
36+
private final List<String> featureProperties;
37+
38+
public FeaturePropertiesMustExistOnAllNodeLabels(List<String> featureProperties) {
39+
this.featureProperties = featureProperties;
40+
}
41+
42+
@Override
43+
protected void validateAlgorithmRequirements(
44+
GraphStore graphStore,
45+
Collection<NodeLabel> selectedLabels,
46+
Collection<RelationshipType> selectedRelationshipTypes
47+
) {
48+
49+
var missingProperties = featureProperties
50+
.stream()
51+
.filter(featureProperty -> !graphStore.hasNodeProperty(selectedLabels, featureProperty))
52+
.collect(Collectors.toList());
53+
54+
if (!missingProperties.isEmpty()) {
55+
throw new IllegalArgumentException(formatWithLocale(
56+
"The feature properties %s are not present for all requested labels. " +
57+
"Requested labels: %s. Properties available on all requested labels: %s",
58+
StringJoining.join(missingProperties),
59+
StringJoining.join(selectedLabels.stream().map(NodeLabel::name)),
60+
StringJoining.join(graphStore.nodePropertyKeys(selectedLabels))
61+
));
62+
}
63+
}
64+
}
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
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.embeddings.validation;
21+
22+
import org.neo4j.gds.api.Graph;
23+
import org.neo4j.gds.core.loading.validation.GraphValidation;
24+
import org.neo4j.gds.utils.StringFormatting;
25+
26+
import static java.lang.Math.multiplyExact;
27+
28+
public class Node2VecGraphValidation implements GraphValidation {
29+
private final int walksPerNode;
30+
private final int walkLength;
31+
32+
public Node2VecGraphValidation(int walksPerNode, int walkLength) {
33+
this.walksPerNode = walksPerNode;
34+
this.walkLength = walkLength;
35+
}
36+
37+
@Override
38+
public void validate(Graph graph) {
39+
try {
40+
var ignored = multiplyExact(
41+
multiplyExact(graph.nodeCount(), walksPerNode),
42+
walkLength
43+
);
44+
} catch (ArithmeticException ex) {
45+
throw new IllegalArgumentException(
46+
StringFormatting.formatWithLocale(
47+
"Aborting execution, running with the configured parameters is likely to overflow: node count: %d, walks per node: %d, walkLength: %d." +
48+
" Try reducing these parameters or run on a smaller graph.",
49+
graph.nodeCount(),
50+
walksPerNode,
51+
walkLength
52+
));
53+
}
54+
}
55+
}

0 commit comments

Comments
 (0)