1313
1414import org .neo4j .graphalgo .GraphAlgoFactory ;
1515import org .neo4j .graphalgo .PathFinder ;
16+ import org .neo4j .graphalgo .impl .util .PathImpl ;
1617import org .neo4j .graphdb .Direction ;
1718import org .neo4j .graphdb .GraphDatabaseService ;
1819import org .neo4j .graphdb .Node ;
1920import org .neo4j .graphdb .Path ;
2021import org .neo4j .graphdb .PathExpanders ;
22+ import org .neo4j .graphdb .Relationship ;
2123import org .neo4j .graphdb .traversal .Evaluation ;
2224import org .neo4j .graphdb .traversal .TraversalDescription ;
2325import org .neo4j .helpers .collection .IteratorUtil ;
2426
2527import java .util .ArrayList ;
2628import java .util .Collection ;
2729import java .util .Collections ;
30+ import java .util .HashMap ;
2831import java .util .HashSet ;
32+ import java .util .Iterator ;
2933import java .util .List ;
3034import java .util .Map ;
3135import java .util .Set ;
@@ -99,14 +103,13 @@ public Map<Integer, List<Cluster>> execute(GraphDatabaseService service) {
99103
100104 private Map <Integer , List <Cluster >> cluster (GraphDatabaseService service ,
101105 Set <Long > bubbleSourcesToCluster , Set <Long > bubbleSourcesToKeepIntact ) {
102- Map <Integer , List <Cluster >> bubblesClustered = bubbleSourcesToCluster .stream ()
106+ Stream < Map <Integer , List <Cluster > >> bubblesClustered = bubbleSourcesToCluster .stream ()
103107 .map (service ::getNodeById )
104- .map (source -> collapseBubble (service , source , getSinkFromSource (source )))
105- .collect (Collectors .groupingBy (Cluster ::getStartRank ));
108+ .map (source -> collapseBubble (service , source , getSinkFromSource (source )));
106109 Stream <Map <Integer , List <Cluster >>> singletonClusters = bubbleSourcesToKeepIntact .stream ()
107110 .map (service ::getNodeById )
108111 .map (source -> getSingletonClusters (service , source , getSinkFromSource (source )));
109- return mergeMaps (Stream .concat (Stream . of ( bubblesClustered ) , singletonClusters ));
112+ return mergeMaps (Stream .concat (bubblesClustered , singletonClusters ));
110113 }
111114
112115 private static Node getSinkFromSource (Node source ) {
@@ -132,22 +135,41 @@ private Cluster createSingletonCluster(GraphDatabaseService service, Node n) {
132135 Collections .singletonList (sn ), sn .getAnnotations ());
133136 }
134137
135- private Cluster collapseBubble (GraphDatabaseService service , Node source , Node sink ) {
138+ private Map <Integer , List <Cluster >> collapseBubble (GraphDatabaseService service ,
139+ Node source , Node sink ) {
140+ Map <Integer , List <Cluster >> res = new HashMap <>(2 + 1 ); // source + sink + bubble.
136141 int sourceRank = (int ) source .getProperty (SequenceProperties .RANK .name ());
137142 int sinkRank = (int ) sink .getProperty (SequenceProperties .RANK .name ());
143+ // Set the rank of the cluster to be in the middle.
138144 int clusterRank = sourceRank + (sinkRank - sourceRank ) / 2 ;
145+ res .put (sourceRank , Collections .singletonList (createSingletonCluster (service , source )));
146+ res .put (sinkRank , Collections .singletonList (createSingletonCluster (service , sink )));
147+
139148 PathFinder <Path > withinBubble = pathFinderBetweenRanks (sourceRank , sinkRank );
140- // FIXME: don't collapse source and sink, keep those intact.
141149 List <EnrichedSequenceNode > nodes = stream (
142150 withinBubble .findAllPaths (source , sink ))
143- .flatMap (path -> stream (path .nodes ()))
151+ .flatMap (path -> stream (trimPath ( path ) .nodes ()))
144152 .distinct ()
145153 .map (n -> new Neo4jSequenceNode (service , n ))
146154 .collect (Collectors .toList ());
147155 List <Annotation > annotations = nodes .stream ()
148156 .flatMap (e -> e .getAnnotations ().stream ())
149157 .collect (Collectors .toList ());
150- return new Cluster (clusterRank , nodes , annotations );
158+ Cluster cluster = new Cluster (clusterRank , nodes , annotations );
159+ res .put (clusterRank , Collections .singletonList (cluster ));
160+ return res ;
161+ }
162+
163+ private Path trimPath (Path path ) {
164+ Iterator <Node > nodes = path .nodes ().iterator ();
165+ Iterator <Relationship > rels = path .relationships ().iterator ();
166+ nodes .next ();
167+ rels .next ();
168+ PathImpl .Builder builder = new PathImpl .Builder (nodes .next ());
169+ for (int i = 1 ; i < path .length () - 2 ; i ++) {
170+ builder = builder .push (rels .next ());
171+ }
172+ return builder .build ();
151173 }
152174
153175 private PathFinder <Path > pathFinderBetweenRanks (int minRank , int maxRank ) {
0 commit comments