1919 */
2020package org .neo4j .gds .beta .undirected ;
2121
22+ import org .jetbrains .annotations .NotNull ;
2223import org .neo4j .gds .Algorithm ;
2324import org .neo4j .gds .Orientation ;
2425import org .neo4j .gds .RelationshipType ;
2526import org .neo4j .gds .api .CompositeRelationshipIterator ;
27+ import org .neo4j .gds .api .Graph ;
2628import org .neo4j .gds .api .GraphStore ;
2729import org .neo4j .gds .api .PropertyState ;
30+ import org .neo4j .gds .api .RelationshipIterator ;
2831import org .neo4j .gds .api .RelationshipProperty ;
2932import org .neo4j .gds .api .RelationshipPropertyStore ;
3033import org .neo4j .gds .api .schema .Direction ;
3134import org .neo4j .gds .api .schema .PropertySchema ;
35+ import org .neo4j .gds .api .schema .RelationshipPropertySchema ;
3236import org .neo4j .gds .core .concurrency .RunWithConcurrency ;
3337import org .neo4j .gds .core .loading .SingleTypeRelationshipImportResult ;
3438import org .neo4j .gds .core .loading .construction .GraphFactory ;
39+ import org .neo4j .gds .core .loading .construction .RelationshipsAndDirection ;
3540import org .neo4j .gds .core .loading .construction .RelationshipsBuilder ;
3641import org .neo4j .gds .core .loading .construction .RelationshipsBuilderBuilder ;
3742import org .neo4j .gds .core .utils .partition .DegreePartition ;
4247import java .util .List ;
4348import java .util .Optional ;
4449import java .util .concurrent .ExecutorService ;
50+ import java .util .function .Function ;
4551import java .util .stream .Collectors ;
4652import java .util .stream .IntStream ;
4753
@@ -75,30 +81,9 @@ public SingleTypeRelationshipImportResult compute() {
7581 .propertySchemasFor (fromRelationshipType );
7682 var propertyKeys = propertySchemas .stream ().map (PropertySchema ::key ).collect (Collectors .toList ());
7783
78- RelationshipsBuilderBuilder relationshipsBuilderBuilder = GraphFactory .initRelationshipsBuilder ()
79- .concurrency (config .concurrency ())
80- .nodes (graphStore .nodes ())
81- .executorService (executorService )
82- .orientation (Orientation .UNDIRECTED )
83- .validateRelationships (false );
84-
85- propertySchemas .forEach (propertySchema ->
86- relationshipsBuilderBuilder .addPropertyConfig (propertySchema .aggregation (), propertySchema .defaultValue ())
87- );
84+ var relationshipsBuilder = initializeRelationshipsBuilder (propertySchemas );
8885
89- RelationshipsBuilder relationshipsBuilder = relationshipsBuilderBuilder .build ();
90-
91- CompositeRelationshipIterator relationshipIterator = graphStore .getCompositeRelationshipIterator (
92- fromRelationshipType ,
93- propertyKeys
94- );
95-
96- List <ToUndirectedTask > tasks = PartitionUtils .degreePartition (
97- graphStore .getGraph (fromRelationshipType ),
98- config .concurrency (),
99- (partition ) -> new ToUndirectedTask (relationshipsBuilder , relationshipIterator .concurrentCopy (), partition , progressTracker ),
100- Optional .empty ()
101- );
86+ var tasks = createTasks (fromRelationshipType , propertyKeys , relationshipsBuilder );
10287
10388 progressTracker .beginSubTask ();
10489
@@ -117,6 +102,38 @@ public SingleTypeRelationshipImportResult compute() {
117102 var relationships = relationshipsBuilder .buildAll ();
118103 progressTracker .endSubTask ();
119104
105+ SingleTypeRelationshipImportResult result = createResult (
106+ propertySchemas ,
107+ propertyKeys ,
108+ relationships
109+ );
110+
111+ progressTracker .endSubTask ();
112+
113+ return result ;
114+ }
115+
116+ @ NotNull
117+ private RelationshipsBuilder initializeRelationshipsBuilder (List <RelationshipPropertySchema > propertySchemas ) {
118+ RelationshipsBuilderBuilder relationshipsBuilderBuilder = GraphFactory .initRelationshipsBuilder ()
119+ .concurrency (config .concurrency ())
120+ .nodes (graphStore .nodes ())
121+ .executorService (executorService )
122+ .orientation (Orientation .UNDIRECTED )
123+ .validateRelationships (false );
124+
125+ propertySchemas .forEach (propertySchema ->
126+ relationshipsBuilderBuilder .addPropertyConfig (propertySchema .aggregation (), propertySchema .defaultValue ())
127+ );
128+
129+ return relationshipsBuilderBuilder .build ();
130+ }
131+
132+ private static SingleTypeRelationshipImportResult createResult (
133+ List <RelationshipPropertySchema > propertySchemas ,
134+ List <String > propertyKeys ,
135+ List <RelationshipsAndDirection > relationships
136+ ) {
120137 var topology = relationships .get (0 ).relationships ().topology ();
121138 var propertyValues = IntStream .range (0 , propertyKeys .size ())
122139 .boxed ()
@@ -136,27 +153,96 @@ public SingleTypeRelationshipImportResult compute() {
136153 .putAllRelationshipProperties (propertyValues )
137154 .build ();
138155
139- progressTracker .endSubTask ();
140156 return SingleTypeRelationshipImportResult .builder ()
141157 .topology (topology )
142158 .properties (propertyStore )
143159 .direction (Direction .UNDIRECTED )
144160 .build ();
145161 }
146162
163+ @ NotNull
164+ private List <Runnable > createTasks (
165+ RelationshipType fromRelationshipType ,
166+ List <String > propertyKeys ,
167+ RelationshipsBuilder relationshipsBuilder
168+ ) {
169+ Function <DegreePartition , Runnable > taskCreator ;
170+ if (propertyKeys .size () == 1 ) {
171+ Graph graph = graphStore .getGraph (fromRelationshipType , Optional .of (propertyKeys .get (0 )));
172+
173+ taskCreator = (partition ) -> new ToUndirectedTaskWithSingleProperty (
174+ relationshipsBuilder ,
175+ graph .concurrentCopy (),
176+ partition ,
177+ progressTracker
178+ );
179+ }
180+ else {
181+ CompositeRelationshipIterator relationshipIterator = graphStore .getCompositeRelationshipIterator (
182+ fromRelationshipType ,
183+ propertyKeys
184+ );
185+
186+ taskCreator = (partition ) -> new ToUndirectedTaskWithMultipleProperties (
187+ relationshipsBuilder ,
188+ relationshipIterator .concurrentCopy (),
189+ partition ,
190+ progressTracker
191+ );
192+ }
193+
194+ return PartitionUtils .degreePartition (
195+ graphStore .getGraph (fromRelationshipType ),
196+ config .concurrency (),
197+ taskCreator ,
198+ Optional .empty ()
199+ );
200+ }
201+
147202 @ Override
148203 public void release () {
149204
150205 }
151206
152- private static final class ToUndirectedTask implements Runnable {
207+ private static final class ToUndirectedTaskWithSingleProperty implements Runnable {
208+
209+ private final RelationshipsBuilder relationshipsBuilder ;
210+ private final RelationshipIterator relationshipIterator ;
211+ private final DegreePartition partition ;
212+ private final ProgressTracker progressTracker ;
213+
214+ private ToUndirectedTaskWithSingleProperty (
215+ RelationshipsBuilder relationshipsBuilder ,
216+ RelationshipIterator relationshipIterator ,
217+ DegreePartition partition ,
218+ ProgressTracker progressTracker
219+ ) {
220+ this .relationshipsBuilder = relationshipsBuilder ;
221+ this .relationshipIterator = relationshipIterator ;
222+ this .partition = partition ;
223+ this .progressTracker = progressTracker ;
224+ }
225+
226+ @ Override
227+ public void run () {
228+ for (long i = partition .startNode (); i < partition .startNode () + partition .nodeCount (); i ++) {
229+ relationshipIterator .forEachRelationship (i , 0.0D , (source , target , property ) -> {
230+ relationshipsBuilder .addFromInternal (target , source , property );
231+ return true ;
232+ });
233+ progressTracker .logProgress ();
234+ }
235+ }
236+ }
237+
238+ private static final class ToUndirectedTaskWithMultipleProperties implements Runnable {
153239
154240 private final RelationshipsBuilder relationshipsBuilder ;
155241 private final CompositeRelationshipIterator relationshipIterator ;
156242 private final DegreePartition partition ;
157243 private final ProgressTracker progressTracker ;
158244
159- private ToUndirectedTask (
245+ private ToUndirectedTaskWithMultipleProperties (
160246 RelationshipsBuilder relationshipsBuilder ,
161247 CompositeRelationshipIterator relationshipIterator ,
162248 DegreePartition partition ,
@@ -172,7 +258,7 @@ private ToUndirectedTask(
172258 public void run () {
173259 for (long i = partition .startNode (); i < partition .startNode () + partition .nodeCount (); i ++) {
174260 relationshipIterator .forEachRelationship (i , (source , target , properties ) -> {
175- relationshipsBuilder .add (target , source , properties );
261+ relationshipsBuilder .addFromInternal (target , source , properties );
176262 return true ;
177263 });
178264 progressTracker .logProgress ();
0 commit comments