Search code examples
cypheragens-graph

cypher flip flop sequence: traversal with alternate edge directions (AgensGraph)


Suppose, we model couples with 2 vertex labels, female and male, and with a single edge label, dates. The direction of the edge is always from female to male.

The expected query result list are couples, where there is a non-directed path from a start vertex to the vertices of each couple, distinct.

In other words the result should contain the edge list of the connected components of the graph, where the given vertex is present.

Please note, that there can be loops if the original graph is converted to a non-directed graph.

Sample graph

Filter criterion: { name: 'Adam' }

Expected result set:

Alice-[:dates]->Adam
Alice-[:dates]->Bob
Chloe-[:dates]->Bob
...
Eve-[:dates]->Edgar

Uhura-[:dates]->Spock is NOT part of the result set, since there is no connection between Adam and (Uhura or Spock).

The following solution works, but it has poor performance, so it can't be used in production:

match path = ()-[:dates*]-()
where any(node in to_jsonb(nodes(path)) where node.properties.name = 'Adam')
return distinct path;

(Or return distinct edges(path), but AgensBrowser does not like to return the edges of a path).

Could you please help me with some advices for a better solution? Thanks.

Test data:

create
  (alice: female { name: 'Alice'}),
  (barbara: female { name: 'Barbara'}),
  (chloe: female { name: 'Chloe'}),
  (diane: female { name: 'Diane'}),
  (eve: female { name: 'Eve'}),
  (uhura: female { name: 'Uhura'}),
  (adam: male { name: 'Adam'}),
  (bob: male { name: 'Bob'}),
  (charles: male { name: 'Charles'}),
  (daniel: male { name: 'Daniel'}),
  (edgar: male { name: 'Edgar'}),
  (spock: male { name: 'Spock'})
create (alice)-[:dates]->(adam),
  (alice)-[:dates]->(bob),
  (barbara)-[:dates]->(bob),
  (barbara)-[:dates]->(charles),
  (barbara)-[:dates]->(edgar),
  (chloe)-[:dates]->(bob),
  (chloe)-[:dates]->(daniel),
  (chloe)-[:dates]->(edgar),
  (diane)-[:dates]->(edgar),
  (eve)-[:dates]->(edgar),
  (uhura)-[:dates]->(spock);

Solution

  • I tried to reenact your query in Agensgraph, but the last match query did not work for me, so I wasn't able to check out its explain.

    Here is the query I made to retrieve the same result you want to.

    match (f:female)<-[r:dates*]->(m:male{name:'Adam'}) with distinct f
    match p = ((f)-[:dates]->(m:male)) return p;
    
    --------------------------------------------------------------------------
    [female[73.1]{"name": "Alice"},dates[71.23][73.1,74.1]{},male[74.1]{"name": "Adam"}]
    [female[73.1]{"name": "Alice"},dates[71.24][73.1,74.2]{},male[74.2]{"name": "Bob"}]
    [female[73.2]{"name": "Barbara"},dates[71.25][73.2,74.2]{},male[74.2]{"name": "Bob"}]
    [female[73.2]{"name": "Barbara"},dates[71.26][73.2,74.3]{},male[74.3]{"name": "Charles"}]
    [female[73.2]{"name": "Barbara"},dates[71.27][73.2,74.5]{},male[74.5]{"name": "Edgar"}]
    [female[73.3]{"name": "Chloe"},dates[71.28][73.3,74.2]{},male[74.2]{"name": "Bob"}]
    [female[73.3]{"name": "Chloe"},dates[71.29][73.3,74.4]{},male[74.4]{"name": "Daniel"}]
    [female[73.3]{"name": "Chloe"},dates[71.30][73.3,74.5]{},male[74.5]{"name": "Edgar"}]
    [female[73.4]{"name": "Diane"},dates[71.31][73.4,74.5]{},male[74.5]{"name": "Edgar"}]
    [female[73.5]{"name": "Eve"},dates[71.32][73.5,74.5]{},male[74.5]{"name": "Edgar"}]
    (10 rows)
    

    Frankly saying, I am not so sure about the performance of above query when the volume of data is huge.

    Please leave me the feedback after running the query.

    Edited on 25 Mar.

    Could this be the solution for your case?

    match p = allshortestpaths( (f:female)<-[r:dates*]->(m:male) )
    where any(node in to_jsonb(nodes(p)) where node.properties.name starts with 'Adam' )
    return p;
    

    enter image description here