1

I am fairly new to gremlin query and janusgraph. I had a requirement to get both edges and nodes of the graph given various properties of the nodes and the relationship between them. There can be multiple properties and/or relationships and a logical operator between them.

After a good amount of research and going through PRACTICAL GREMLIN: An Apache Tinkerpop Tutorial I figured a way to do this in a single query., i.e, using path() step.

For example a simple query with one property or relationship filter would look like this:

g.V().hasLabel("label").has("prop1", eq("prop1-value").path().toList()

g.V().hasLabel("label").outE("relation1").inV().hasLabel("related_node").path().toList()

Such queries worked fine, where the result contained both edges and nodes whenever there is a relationship involved in the query.

However, for complex queries where multiple relationships or combination of relationship and properties are involved, the query doesnt return edges. It only returns nodes. For example:

g.V().hasLabel("label").and(has("prop1", eq("prop1-value"), outE("relation1").inV().hasLabel("related_node")).path().toList()

g.V().hasLabel("label").or(has("prop1", eq("prop1-value"), outE("relation1").inV().hasLabel("related_node")).path().toList()

g.V().hasLabel("label").or(inE("relation2").outV().hasLabel("another_node"), outE("relation1").inV().hasLabel("related_node")).path().toList()

Why doesnt the path() step doesnt include the edges in such cases mentioned above? Any help is much appreciated.

Note: The gremlin query is constructed in Java using gremlin-java.

I have also tried to use select step which didn't help.

1 Answer 1

1

Gremlin maintains a path history to keep track of where he has travelled in a graph and that is what the path() step produces. The and() and or() steps are filters and filters don't change the state of that history (Gremlin really doesn't move anywhere on a filter the way you might with outE() or in() or other map()-like steps that transform the current traverser state). In your example:

g.V().hasLabel("label").
  and(has("prop1", eq("prop1-value"),
      outE("relation1").inV().hasLabel("related_node")).
  path()

you do have some traversing steps like outE() but they apply to the filter to "check for outgoing edges" but not to actually traverse to them to change the path history. If you want to see the edges in the path then you would need to explicitly traverse to them after the filter. I'd perhaps rewrite that as:

g.V().has("label", "prop1", "prop1-value")
  outE("relation1").inV().hasLabel("related_node").
  path()

That seems like an analogous traversal to what you were writing because the and() is implied and you want the Path object not just the initial Vertex on that Path.

If you have multiple directions to traverse, the above suggestion might not work so well, nor will it work for and() situations where you want to ensure both filtering conditions are present. Most directly I guess you could do:

g.V().
  hasLabel("label").
  and(inE("relation2").outV().hasLabel("another_node"),
      outE("relation1").inV().hasLabel("related_node")).
  union(inE("relation2").outV().hasLabel("another_node"),
        outE("relation1").inV().hasLabel("related_node")).
  path()

but that will likely traverse both paths twice, once to filter and once to gather the data for the path(). That might not be bad depending on the cost of the filter (i.e. how many edges needed to be tested to satisfy the and()).

Another option would be to gather all the paths and then try to post filter them (rather than filtering up front with and()):

g.V().
  hasLabel("label").
  union(inE("relation2").outV().hasLabel("another_node"),
        outE("relation1").inV().hasLabel("related_node")).
  path().
  group().
    by(limit(local,1)).
  unfold().
  select(values).
  filter(count(local).is(gt(1)))

Your filter is going to be domain specific in that you'll need to know rules about cardinality within your data to make write it. In my example above, I just assumed that if there is single cardinality for each of those edges such that having more than one path count per starting vertex would mean that the and() semantics was satisfied.

Sign up to request clarification or add additional context in comments.

5 Comments

What about Or() case?
Also what about a case where you have an Or between two relationships: For example: g.V().hasLabel("label").or(inE("relation2").outV().hasLabel("another_node"), outE("relation1").inV().hasLabel("related_node")).path().toList()
convert or() to union().
How to handle such queries for example: g.V().hasLabel("label").and(inE("relation2").outV().hasLabel("another_node"), outE("relation1").inV().hasLabel("related_node")).path().toList() This will not give the path. We can even append them back to back.
updated my answer based on your comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.