Search code examples
gremlintinkerpop3tinkerpop

Check if the graph matches two non-overlapping patterns


enter image description here

Given this ultra-simple graph, with unknown number of vertices between A and Z, I can easily check if a specific pattern is satisfied, e.g.

Is there a vertex named "B" eventually followed by "D"?

would be answered by:

boolean matches = g.V().match(
            as("b").has("name", "B"),
            as("b").repeat(out()).until(has("name", "D")).as("d")
        )
        .hasNext();

But how would I check if 2 (or more) non-overlapping patterns are satisfied? E.g.

Is there also a vertex named "G" eventually followed by "J"?

I'd naturally do:

boolean matches = g.V().match(
            as("b").has("name", "B"),
            as("b").repeat(out()).until(has("name", "D")).as("d"),
            as("g").has("name", "G"),
            as("g").repeat(out()).until(has("name", "J")).as("j")
        )
       .hasNext(); 

But this gives me the dreaded The provided match pattern is unsolvable. Not sure why this would be problematic...

I can of course re-start the traversal from g.V() and try each match individually, but I'm trying to understand if that would really be necessary and, if so, why.


Solution

  • Union step is what you need.

    g.V().
      union(
        match(
          __.as('a').has("name", "marko").as('b'),
          __.as('b').repeat(out()).until(has("name", "vadas")).as('c')).
        select('a', 'c'),
        match(
          __.as('d').has("name", "marko").as('e'),
          __.as('e').repeat(out()).until(has("name", "ripple")).as('f')).
        select('d', 'f')).
      unfold().
      fold()
    

    You can add as many as matching patterns in the union. Union will run child traversal on incoming V() traversal output.

    PS: I ran this query on modern graph as per tinkerpop documentation.