Skip to content

Commit 5f19382

Browse files
committed
Consider case without label, but properties
1 parent 9cced6a commit 5f19382

File tree

5 files changed

+90
-11
lines changed

5 files changed

+90
-11
lines changed

core/src/main/java/org/neo4j/gds/api/CSRGraphStoreFactory.java

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -42,10 +42,7 @@ public CSRGraphStoreFactory(
4242
super(graphProjectConfig, capabilities, loadingContext, dimensions);
4343
}
4444

45-
protected CSRGraphStore createGraphStore(
46-
Nodes nodes,
47-
RelationshipImportResult relationshipImportResult
48-
) {
45+
protected CSRGraphStore createGraphStore(Nodes nodes, RelationshipImportResult relationshipImportResult) {
4946
return new GraphStoreBuilder()
5047
.databaseId(DatabaseId.of(loadingContext.graphDatabaseService()))
5148
.capabilities(capabilities)

core/src/main/java/org/neo4j/gds/core/loading/CypherFactory.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -148,7 +148,7 @@ public CSRGraphStore build() {
148148
progressTracker
149149
).load(ktx.internalTransaction());
150150

151-
var relationshipsAndProperties = new CypherRelationshipLoader(
151+
var relationshipImportResult = new CypherRelationshipLoader(
152152
relationshipQuery(),
153153
nodes.idMap(),
154154
cypherConfig,
@@ -158,7 +158,7 @@ public CSRGraphStore build() {
158158

159159
var graphStore = createGraphStore(
160160
nodes,
161-
relationshipsAndProperties
161+
relationshipImportResult
162162
);
163163

164164
progressTracker.endSubTask("Loading");

core/src/main/java/org/neo4j/gds/core/loading/construction/NodeLabelTokenToPropertyKeys.java

Lines changed: 26 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929
import java.util.Set;
3030
import java.util.concurrent.ConcurrentHashMap;
3131
import java.util.stream.Collectors;
32+
import java.util.stream.IntStream;
3233

3334
abstract class NodeLabelTokenToPropertyKeys {
3435

@@ -57,6 +58,11 @@ static NodeLabelTokenToPropertyKeys fixed(NodeSchema nodeSchema) {
5758
*/
5859
abstract void add(NodeLabelToken nodeLabelToken, Iterable<String> propertyKeys);
5960

61+
/**
62+
* Returns all node labels in this mapping.
63+
*/
64+
abstract Set<NodeLabel> nodeLabels();
65+
6066
/**
6167
* Return the property schemas for the given node label.
6268
*/
@@ -78,6 +84,11 @@ void add(NodeLabelToken nodeLabelToken, Iterable<String> propertyKeys) {
7884
// silence is golden
7985
}
8086

87+
@Override
88+
Set<NodeLabel> nodeLabels() {
89+
return nodeSchema.availableLabels();
90+
}
91+
8192
@Override
8293
Map<String, PropertySchema> propertySchemas(
8394
NodeLabel nodeLabel,
@@ -120,7 +131,6 @@ Map<String, PropertySchema> propertySchemas(
120131
);
121132
}
122133

123-
124134
return userDefinedPropertySchemas;
125135
}
126136
}
@@ -140,7 +150,16 @@ void add(NodeLabelToken nodeLabelToken, Iterable<String> propertyKeys) {
140150
propertyKeys.forEach(keys::add);
141151
return keys;
142152
});
153+
}
143154

155+
@Override
156+
Set<NodeLabel> nodeLabels() {
157+
return labelToPropertyKeys
158+
.keySet()
159+
.stream()
160+
.map(nodeLabelToken -> nodeLabelToken.isEmpty() ? NodeLabelTokens.ofNodeLabel(NodeLabel.ALL_NODES) : nodeLabelToken)
161+
.flatMap(nodeLabelToken -> IntStream.range(0, nodeLabelToken.size()).mapToObj(nodeLabelToken::get))
162+
.collect(Collectors.toSet());
144163
}
145164

146165
@Override
@@ -150,7 +169,11 @@ Map<String, PropertySchema> propertySchemas(
150169
) {
151170
return labelToPropertyKeys.keySet().stream()
152171
.filter(nodeLabelToken -> {
153-
for (int i = 0; i < nodeLabelToken.size(); i++) {
172+
if (nodeLabelToken.isEmpty() && nodeLabel == NodeLabel.ALL_NODES) {
173+
return true;
174+
}
175+
var nodeLabelTokenCount = nodeLabelToken.size();
176+
for (int i = 0; i < nodeLabelTokenCount; i++) {
154177
if (nodeLabelToken.get(i).equals(nodeLabel)) {
155178
return true;
156179
}
@@ -162,7 +185,7 @@ Map<String, PropertySchema> propertySchemas(
162185
propertyKey -> propertyKey,
163186
importPropertySchemas::get,
164187
(lhs, rhs) -> lhs
165-
));
188+
));
166189
}
167190
}
168191
}

core/src/main/java/org/neo4j/gds/core/loading/construction/NodesBuilder.java

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@
5050
import org.neo4j.values.virtual.MapValue;
5151

5252
import java.util.ArrayList;
53+
import java.util.HashSet;
5354
import java.util.List;
5455
import java.util.Map;
5556
import java.util.Optional;
@@ -223,9 +224,18 @@ private NodeSchema buildNodeSchema(IdMap idMap, Map<String, NodeProperty> nodePr
223224
.stream()
224225
.collect(Collectors.toMap(Map.Entry::getKey, entry -> entry.getValue().propertySchema()));
225226

226-
idMap.availableNodeLabels().forEach(label -> {
227-
nodeSchema.addLabel(label, this.nodeLabelTokenToPropertyKeys.propertySchemas(label, importPropertySchemas));
227+
// consider node labels without properties
228+
var nodeLabels = new HashSet<>(idMap.availableNodeLabels());
229+
// and also node labels with associated properties
230+
nodeLabels.addAll(nodeLabelTokenToPropertyKeys.nodeLabels());
231+
232+
nodeLabels.forEach(nodeLabel -> {
233+
nodeSchema.addLabel(
234+
nodeLabel,
235+
this.nodeLabelTokenToPropertyKeys.propertySchemas(nodeLabel, importPropertySchemas)
236+
);
228237
});
238+
229239
return nodeSchema;
230240
}
231241

core/src/test/java/org/neo4j/gds/core/loading/construction/NodeLabelTokenToPropertyKeysTest.java

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -160,5 +160,54 @@ void testDuplicatePropertyKeys() {
160160
"bar", PropertySchema.of("bar", ValueType.DOUBLE, DefaultValue.forDouble(), PropertyState.PERSISTENT)
161161
));
162162
}
163+
164+
@Test
165+
void testEmptyNodeLabelTokenResolvesToAllNodes() {
166+
var mapping = NodeLabelTokenToPropertyKeys.lazy();
167+
mapping.add(NodeLabelTokens.empty(), List.of("foo", "bar"));
168+
169+
var importPropertySchemas = Map.of(
170+
"foo", PropertySchema.of("foo", ValueType.LONG, DefaultValue.forLong(), PropertyState.TRANSIENT),
171+
"bar", PropertySchema.of("bar", ValueType.DOUBLE, DefaultValue.forDouble(), PropertyState.PERSISTENT)
172+
);
173+
174+
assertThat(mapping.propertySchemas(NodeLabel.ALL_NODES, importPropertySchemas)).isEqualTo(Map.of(
175+
"foo", PropertySchema.of("foo", ValueType.LONG, DefaultValue.forLong(), PropertyState.TRANSIENT),
176+
"bar", PropertySchema.of("bar", ValueType.DOUBLE, DefaultValue.forDouble(), PropertyState.PERSISTENT)
177+
));
178+
}
179+
180+
@Test
181+
void testNodeLabelsLazily() {
182+
var mapping = NodeLabelTokenToPropertyKeys.lazy();
183+
mapping.add(NodeLabelTokens.empty(), List.of("foo"));
184+
mapping.add(NodeLabelTokens.of("A"), List.of("bar"));
185+
mapping.add(NodeLabelTokens.ofStrings("A", "B"), List.of("baz"));
186+
mapping.add(NodeLabelTokens.ofStrings("B", "C"), List.of("buz"));
187+
188+
assertThat(mapping.nodeLabels()).containsExactlyInAnyOrder(
189+
NodeLabel.ALL_NODES,
190+
NodeLabel.of("A"),
191+
NodeLabel.of("B"),
192+
NodeLabel.of("C")
193+
);
194+
}
195+
196+
@Test
197+
void testNodeLabelsFixed() {
198+
var mapping = NodeLabelTokenToPropertyKeys.fixed(NodeSchema.empty()
199+
.addLabel(NodeLabel.ALL_NODES)
200+
.addLabel(NodeLabel.of("A"))
201+
.addLabel(NodeLabel.of("B"))
202+
.addLabel(NodeLabel.of("C"))
203+
);
204+
205+
assertThat(mapping.nodeLabels()).containsExactlyInAnyOrder(
206+
NodeLabel.ALL_NODES,
207+
NodeLabel.of("A"),
208+
NodeLabel.of("B"),
209+
NodeLabel.of("C")
210+
);
211+
}
163212
}
164213

0 commit comments

Comments
 (0)