Skip to content

Commit 666caf9

Browse files
committed
Add targetNodeFilter config
1 parent 5df82da commit 666caf9

File tree

2 files changed

+88
-0
lines changed

2 files changed

+88
-0
lines changed

algo/src/main/java/org/neo4j/gds/similarity/filteredknn/FilteredKnnBaseConfig.java

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,12 @@ default List<Long> sourceNodeFilter() {
4545
return List.of();
4646
}
4747

48+
@Value.Default
49+
@Configuration.LongRange(min = 0)
50+
default List<Long> targetNodeFilter() {
51+
return List.of();
52+
}
53+
4854
@Configuration.GraphStoreValidationCheck
4955
default void validateSourceNodeFilter(
5056
GraphStore graphStore,
@@ -66,4 +72,24 @@ default void validateSourceNodeFilter(
6672
}
6773
}
6874

75+
@Configuration.GraphStoreValidationCheck
76+
default void validateTargetNodeFilter(
77+
GraphStore graphStore,
78+
Collection<NodeLabel> selectedLabels,
79+
Collection<RelationshipType> selectedRelationshipTypes
80+
) {
81+
var nodes = graphStore.nodes();
82+
var missingNodes = targetNodeFilter()
83+
.stream()
84+
.filter(n -> nodes.toMappedNodeId(n) == IdMap.NOT_FOUND)
85+
.collect(Collectors.toList());
86+
if (!missingNodes.isEmpty()) {
87+
throw new IllegalArgumentException(
88+
formatWithLocale(
89+
"Invalid configuration value 'targetNodeFilter', the following nodes are missing from the graph: %s",
90+
missingNodes
91+
)
92+
);
93+
}
94+
}
6995
}

algo/src/test/java/org/neo4j/gds/similarity/filteredknn/FilteredKnnBaseConfigTest.java

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,22 @@ void shouldAcceptValidSourceNodeFilter() {
6161
);
6262
}
6363

64+
@Test
65+
void shouldAcceptValidTargetNodeFilter() {
66+
new FilteredKnnBaseConfigImpl(
67+
CypherMapWrapper.create(
68+
Map.of(
69+
"nodeProperties", List.of("dummy"),
70+
"targetNodeFilter", List.of(idFunction.of("a"))
71+
)
72+
)
73+
).validateSourceNodeFilter(
74+
graphStore,
75+
List.of(),
76+
List.of()
77+
);
78+
}
79+
6480
@Test
6581
void shouldRejectOutOfRangeSourceNodeFilter() {
6682
var outOfRangeNode = -1L;
@@ -77,6 +93,22 @@ void shouldRejectOutOfRangeSourceNodeFilter() {
7793
.hasMessage("Value for `sourceNodeFilter` was `" + outOfRangeNode + "`, but must be within the range [0, 9223372036854775807].");
7894
}
7995

96+
@Test
97+
void shouldRejectOutOfRangeTargetNodeFilter() {
98+
var outOfRangeNode = -1L;
99+
assertThatThrownBy(
100+
() -> new FilteredKnnBaseConfigImpl(
101+
CypherMapWrapper.create(
102+
Map.of(
103+
"nodeProperties", List.of("dummy"),
104+
"targetNodeFilter", List.of(outOfRangeNode)
105+
)
106+
)
107+
)
108+
).isInstanceOf(IllegalArgumentException.class)
109+
.hasMessage("Value for `targetNodeFilter` was `" + outOfRangeNode + "`, but must be within the range [0, 9223372036854775807].");
110+
}
111+
80112
@Test
81113
void shouldRejectSourceNodeFilterWithMissingNode() {
82114
//noinspection OptionalGetWithoutIsPresent
@@ -106,4 +138,34 @@ void shouldRejectSourceNodeFilterWithMissingNode() {
106138
.hasMessage(
107139
"Invalid configuration value 'sourceNodeFilter', the following nodes are missing from the graph: [" + missingNode + "]");
108140
}
141+
142+
@Test
143+
void shouldRejectTargetNodeFilterWithMissingNode() {
144+
//noinspection OptionalGetWithoutIsPresent
145+
var missingNode = new Random()
146+
.longs(
147+
0,
148+
4_294_967_295L // a large-ish number that still fits in our id maps (Math.pow(2, 32) - 1)
149+
).filter(l -> !graphStore.nodes().contains(l))
150+
.limit(1)
151+
.findFirst()
152+
.getAsLong();
153+
154+
assertThatThrownBy(
155+
() -> new FilteredKnnBaseConfigImpl(
156+
CypherMapWrapper.create(
157+
Map.of(
158+
"nodeProperties", List.of("dummy"),
159+
"targetNodeFilter", List.of(idFunction.of("a"), missingNode) // one existing, one missing
160+
)
161+
)
162+
).validateTargetNodeFilter(
163+
graphStore,
164+
List.of(),
165+
List.of()
166+
)
167+
).isInstanceOf(IllegalArgumentException.class)
168+
.hasMessage(
169+
"Invalid configuration value 'targetNodeFilter', the following nodes are missing from the graph: [" + missingNode + "]");
170+
}
109171
}

0 commit comments

Comments
 (0)