2525import org .neo4j .gds .api .PropertyState ;
2626import org .neo4j .gds .api .properties .nodes .LongNodePropertyValues ;
2727import org .neo4j .gds .api .properties .nodes .NodeProperty ;
28+ import org .neo4j .gds .collections .HugeSparseLongArray ;
2829import org .neo4j .gds .config .CommunitySizeConfig ;
2930import org .neo4j .gds .config .ConcurrencyConfig ;
3031import org .neo4j .gds .config .ConsecutiveIdsConfig ;
3132import org .neo4j .gds .config .SeedConfig ;
3233import org .neo4j .gds .core .CypherMapWrapper ;
3334import org .neo4j .gds .nodeproperties .ConsecutiveLongNodePropertyValues ;
3435import org .neo4j .gds .nodeproperties .LongIfChangedNodePropertyValues ;
36+ import org .neo4j .values .storable .Values ;
37+
38+ import java .util .Map ;
3539
3640import static org .assertj .core .api .Assertions .assertThat ;
3741
@@ -152,6 +156,60 @@ void shouldWorkWithMinComponentAndConsecutive() {
152156
153157 }
154158
159+ @ Test
160+ void minComponentSizeWithSparseProperties () {
161+ var inputBuilder = HugeSparseLongArray .builder (Long .MIN_VALUE );
162+ inputBuilder .set (1 , 42 );
163+ inputBuilder .set (2 , 99 );
164+ inputBuilder .set (3 , 42 );
165+ var input = inputBuilder .build ();
166+
167+ LongNodePropertyValues sparseProperties = new TestSparseNodePropertyValues (4 , 3 , input ::get );
168+
169+ var config = ConfigWithComponentSize .of (CypherMapWrapper .empty ().withNumber ("minComponentSize" , 2L ));
170+
171+ var filteredProperties = CommunityProcCompanion .nodeProperties (
172+ config ,
173+ "seed" ,
174+ sparseProperties ,
175+ () -> { throw new UnsupportedOperationException ("Not implemented" ); }
176+ );
177+
178+ // null from the beginning
179+ assertThat (filteredProperties .value (0 )).isNull ();
180+ assertThat (filteredProperties .value (1 )).isEqualTo (Values .longValue (42 ));
181+ // filtered out
182+ assertThat (filteredProperties .value (2 )).isNull ();
183+ assertThat (filteredProperties .value (3 )).isEqualTo (Values .longValue (42 ));
184+ }
185+
186+ @ Test
187+ void consecutiveIdsWithSparseProperties () {
188+ var inputBuilder = HugeSparseLongArray .builder (Long .MIN_VALUE );
189+ inputBuilder .set (1 , 42 );
190+ inputBuilder .set (2 , 99 );
191+ inputBuilder .set (3 , 42 );
192+ var input = inputBuilder .build ();
193+
194+ LongNodePropertyValues sparseProperties = new TestSparseNodePropertyValues (4 , 3 , input ::get );
195+
196+ var config = ConfigWithComponentSize .of (CypherMapWrapper .create (Map .of ("minComponentSize" , 2L , "consecutiveIds" , true )));
197+
198+ var filteredProperties = CommunityProcCompanion .nodeProperties (
199+ config ,
200+ "seed" ,
201+ sparseProperties ,
202+ () -> { throw new UnsupportedOperationException ("Not implemented" ); }
203+ );
204+
205+ // null from the beginning
206+ assertThat (filteredProperties .value (0 )).isNull ();
207+ assertThat (filteredProperties .value (1 )).isEqualTo (Values .longValue (0 ));
208+ // filtered out
209+ assertThat (filteredProperties .value (2 )).isNull ();
210+ assertThat (filteredProperties .value (3 )).isEqualTo (Values .longValue (0 ));
211+ }
212+
155213 private static final class TestNodePropertyValues implements LongNodePropertyValues {
156214 private final long size ;
157215 private final LongToLongFunction transformer ;
@@ -175,6 +233,36 @@ public long longValue(long nodeId) {
175233 }
176234 }
177235
236+ private static final class TestSparseNodePropertyValues implements LongNodePropertyValues {
237+ private final long size ;
238+ private final long valuesStored ;
239+ private final LongToLongFunction transformer ;
240+
241+ private TestSparseNodePropertyValues (
242+ long size ,
243+ long valuesStored ,
244+ LongToLongFunction transformer
245+ ) {
246+ this .size = size ;
247+ this .valuesStored = valuesStored ;
248+ this .transformer = transformer ;
249+ }
250+
251+ @ Override
252+ public long valuesStored () {
253+ return valuesStored ;
254+ }
255+
256+ public long size () {
257+ return size ;
258+ }
259+
260+ @ Override
261+ public long longValue (long nodeId ) {
262+ return transformer .applyAsLong (nodeId );
263+ }
264+ }
265+
178266 @ Configuration
179267 interface CommunityProcCompanionConfig extends ConsecutiveIdsConfig , SeedConfig , ConcurrencyConfig , CommunitySizeConfig {
180268 static CommunityProcCompanionConfig of (CypherMapWrapper map ) {
0 commit comments