0

I have created following basic graph:

CREATE (:NodeType1 {prop1:'value1'})-[:RelType1 {prop2:'value2'}]->(:NodeType2 {prop3:'value3'})-[:RelType2 {prop4:'value4'}]->(:NodeType3 {prop5:'value5'})-[:RelType3 {prop6:'value6'}]->(:NodeType4 {prop7:'value7'})

CREATE (:NodeType1 {prop1:'value8'})-[:RelType1 {prop2:'value9'}]->(:NodeType2 {prop3:'value10'})-[:RelType2 {prop4:'value11'}]->(:NodeType3 {prop5:'value12'})-[:RelType3 {prop6:'value13'}]->(:NodeType4 {prop7:'value14'})

MATCH path=(n:NodeType1 {prop1:'value1'})-[*]->(m:NodeType4 {prop7:'value7'})
CREATE (n)-[:RelType1 {prop2:'value15'}]->(:NodeType2 {prop3:'value16'})-[:RelType2 {prop4:'value17'}]->(:NodeType3 {prop5:'value18'})-[:RelType3 {prop6:'value19'}]->(m)

The graph looks like this:

enter image description here

When I run following cypher:

MATCH path=(a:NodeType1 {prop1:"value1"})-[:RelType1]->(b)-[:RelType2]->(c)-[:RelType3]->(d)
RETURN count(nodes(path))

I get 2 as the output. It seems that nodes() doesnt actually return the number nodes in the path but simply the number of rows in the returned result, since if I return the path:

MATCH path=(a:NodeType1 {prop1:"value1"})-[:RelType1]->(b)-[:RelType2]->(c)-[:RelType3]->(d)
RETURN path

I get two rows in the returned result:

enter image description here

Now I am guessing how can I get the same output when doing traversal using Neo4J traversal API. I get number of unique nodes in the cypher as follows:

MATCH path=(a:NodeType1 {prop1:"value1"})-[:RelType1]->(b)-[:RelType2]->(c)-[:RelType3]->(d)
RETURN size(collect(distinct a))+size(collect(distinct b))+size(collect(distinct c))+size(collect(distinct d))

Above query correctly returns 6.

Same can be done in the traversal API by having static counter inside path expander which is incremented each time expand() is called. (Is there any better approach for this?)

public class MyPathExpander implements PathExpander{
    static int nodeCount = 0;

    @Override
    public Iterable expand(Path path, BranchState state) {
        Node lastNode = path.endNode();

        nodeCount++;  //**increment the count of nodes visited

        if(lastNode.hasLabel(MyLabels.NodeType1))
            return lastNode.getRelationships(MyRelations.RelType1, Direction.OUTGOING);
        else if (lastNode.hasRelationship(MyRelations.RelType1, Direction.INCOMING))
            return lastNode.getRelationships(MyRelations.RelType2, Direction.OUTGOING);
        else if (lastNode.hasRelationship(MyRelations.RelType2, Direction.INCOMING))
            return lastNode.getRelationships(MyRelations.RelType3, Direction.OUTGOING);
        else if (lastNode.hasRelationship(MyRelations.RelType3, Direction.INCOMING))
            return null;
        return null;
    }
}

However I am not able to think of way which will tell me number of unique paths followed during traversal while using Traversal API (equivalent to above RETURN count(nodes(path))). How can I do this? Is it not possible with traversal API?

PS: By unique path I mean unique permutations of order of nodes visited while traversing. For example, all a-b-c, a-c-b and a-b-c-d are unique.

Mahesha999
  • 22,693
  • 29
  • 116
  • 189

1 Answers1

0

This query not return count of unique path, but count of all paths return by query:

MATCH path=(a:NodeType1 {prop1:"value1"})-[:RelType1]->(b)
           -[:RelType2]->(c)-[:RelType3]->(d)
RETURN count(nodes(path))

If you want to count the number of unique nodes in the query, you can do so:

MATCH path=(a:NodeType1 {prop1:"value1"})-[:RelType1]->(b)
           -[:RelType2]->(c)-[:RelType3]->(d)
UNWIND nodes(path) AS N
RETURN count(distinct N)

One way to count the number of unique paths will be (for each path calculates its unique fingerprint, it will not be difficult to repeat by traversal API):

MATCH path=(a:NodeType1 {prop1:"value1"})-[:RelType1]->(b)
           -[:RelType2]->(c)-[:RelType3]->(d)
WITH path, 
     REDUCE(acc="", x in nodes(path) | acc + id(x)) +
     REDUCE(acc="", x in rels(path) | acc + id(x)) as uniID    
RETURN count(distinct uniID)
stdob--
  • 28,222
  • 5
  • 58
  • 73
  • Will number of paths and number of unique paths returned by cypher ever be different. I feel both will be same always. – Mahesha999 Feb 16 '17 at 10:18
  • Also its weird that `RETURN nodes(path)` return number of paths, especially when `RETURN path,nodes(path)` correctly returns `path,nodes`. However `RETURN path,count(nodes(path))` return `path,1`, i.e. `1` for all paths. So, I tried to get number of nodes in the path by something like this: `RETURN path,COUNT(UNWIND nodes(path))`. It gives error.I know we can do:`RETURN path,length(path)+1` as number of nodes = 1+number of relationships & `length(path)` return number of relationships. But then can we do it with `COUNT(UNWIND nodes(path))`?so that we can do `COUNT(distinct UNWIND nodes(path))` – Mahesha999 Feb 16 '17 at 11:28