How to use .optional() within a .match() clause correctly? OR How to effectively execute inner-join using a match() step?

618 views
Skip to first unread message

Harsh Thakkar

unread,
Jun 21, 2018, 5:27:20 AM6/21/18
to Gremlin-users
I am not able to comprehend how to do I effectively use optional() within a match() step.

I am working on transpiling/compiling sparql queries to Gremlin traversals (pattern matching style), mostly everything except the optional() clause checks out just fine. However, I am not able to map the optional() operator. 

For reference-


In SPARQL, an optional clause executes an inner-join in the query whereas this is different in the case of Gremlin. e.g.:

SPARQL:

select ?name ?age
where {
?person v:name ?name .
OPTIONAL { ?person v:age ?age .}
}

Here, all person names will be returned regardless of whether or not they have age affiliate to them or not. The age values are optional in this sense. The equivalent query in gremlin should be somewhat like the following, if we were to consider optional() step in Gremlin:

g.V().match(__.as('person').values('name').as('name').optional( __.as('person').values('age').as('age'))).select('name','age')

However, this doesn't work. instead, it throws an error. I am using Gremlin-console v3.3.3


Consider the following gremlin query:

gremlin> g.V().as('a').hasLabel('person').as('person').optional( __.as('a').values('age').as('age')).select('person','age')
==>[person:v[1],age:29]
==>[person:v[2],age:27]
==>[person:v[4],age:32]
==>[person:v[6],age:35]

This works perfectly fine and returns a result. However, if I am to conduct a pattern matching style of a gremlin query, I add a match step in the query encapsulating it within:

gremlin> g.V()..match( __.as('a').hasLabel('person').as('person').optional( __.as('a').values('age').as('age'))).select('person','age')

org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.DefaultGraphTraversal cannot be cast to java.lang.Comparable
Type ':help' or ':h' for help.
 
 However, this throws an error as above. I tried all possible combinations here but always results in one or the other error:

 g.V().match(__.as('person').values('name').as('name'), __as('person').optional(values('age').as('age'))).select('name','age')

No signature of method: groovysh_evaluate.__as() is applicable for argument types: (java.lang.String) values: [person]
Possible solutions: is(java.lang.Object), wait(), run(), run(), find(), any()


What i understood so far is that it is not possible to store values directly  in the variables while using the optional() step, i.e.: 

g.V().as('a').values('name').as('name').optional(__.as('a').values('age').as('age'))).select('name','age')

will not work, because of:
java.lang.String cannot be cast to org.apache.tinkerpop.gremlin.structure.Element


whereas:

gremlin> g.V().as('a').has('name').as('name').optional(__.as('a').values('age').as('age')).select('name','age')
==>[name:v[1],age:29]
==>[name:v[2],age:27]
==>[name:v[4],age:32]
==>[name:v[6],age:35]

Does work fine. I am thinking to not use optional() clause here instead map it to some other operator() such as and() or a workaround to achieve a SQL-like inner join execution. Though no success yet.

If someone could help me fix this, it would be great! 
Cheers,
Harsh



Udit Sharma

unread,
Jun 21, 2018, 6:03:17 AM6/21/18
to gremli...@googlegroups.com
Hi Harsh
Try coalesce instead of optional.
g.V().match(__.as('person').values('name').as('name')).coalesce(match(__.as('person').values('age').as('age')),constant("N/A").as('age')).as('age').select('person','name','age')

--
You received this message because you are subscribed to the Google Groups "Gremlin-users" group.
To unsubscribe from this group and stop receiving emails from it, send an email to gremlin-users+unsubscribe@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/gremlin-users/7ca31bde-a3a5-4c2e-b794-a8d9736bfcad%40googlegroups.com.
For more options, visit https://groups.google.com/d/optout.



--
Thanks and Regards
Udit Sharma

Harsh Thakkar

unread,
Jun 21, 2018, 7:25:16 AM6/21/18
to Gremlin-users
Many thanks Udit! Didn't think of using coalesce. Does the job!
To unsubscribe from this group and stop receiving emails from it, send an email to gremlin-user...@googlegroups.com.

Daniel Kuppitz

unread,
Jun 21, 2018, 10:19:08 AM6/21/18
to gremli...@googlegroups.com
FYI: Two of the errors you've mentioned above (highlighted in red) were only caused by typos in your queries.

g.V()..match( __.as('a').hasLabel('person').as('person').optional( __.as('a').values('age').as('age'))).select('person','age')
     ^^

g.V().match(__.as('person').values('name').as('name'), __as('person').optional(values('age').as('age'))).select('name','age')
                                                       ^^^^
Cheers,
Daniel


To unsubscribe from this group and stop receiving emails from it, send an email to gremlin-users+unsubscribe@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/gremlin-users/d8183ffd-35de-475f-bbc3-404a2db5e8f6%40googlegroups.com.

Harsh Thakkar

unread,
Jun 27, 2018, 7:41:27 AM6/27/18
to Gremlin-users
Right, that was naive of me. 

However, having a has() or values() step before the optional doesn't work. Though I found Udit's suggestion works just fine :)

Harsh Thakkar

unread,
Jul 19, 2018, 6:40:37 AM7/19/18
to Gremlin-users
Another related question: How are you passing the constant step in the java code? could you please share the exact code? I am having issues with the same (in java-gremlin dialect)


On Thursday, 21 June 2018 12:03:17 UTC+2, Udit Sharma wrote:
To unsubscribe from this group and stop receiving emails from it, send an email to gremlin-user...@googlegroups.com.

Daniel Kuppitz

unread,
Jul 19, 2018, 12:22:27 PM7/19/18
to gremli...@googlegroups.com
constant() is like any other step, nothing special about it. What issues are you talking about? Which query are you looking at?

Cheers,
Daniel


To unsubscribe from this group and stop receiving emails from it, send an email to gremlin-users+unsubscribe@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/gremlin-users/2875e7cf-6fdb-4b4a-bcad-c1d7368f70ae%40googlegroups.com.

Harsh Thakkar

unread,
Jul 20, 2018, 12:11:44 PM7/20/18
to Gremlin-users
Consider the following SPARQL and Gremlin queries:

====== SPARQL =========

SELECT ?name ?fname ?age WHERE {
  ?person v:label "person" .
  ?person v:name ?name .
  ?person e:knows ?friend .
  ?friend v:name ?fname .
  OPTIONAL { ?friend v:age ?age . FILTER (?age <= 30) . }
}


========== GREMLIN ===========

g.V().match(__.as('person').hasLabel('person'), __.as('person').values('name').as('name'), __.as('person').out('knows').as('friend'), __.as('friend').values('name').as('fname')).coalesce(match(__.as('friend').values('age').is(lte(30)).as('age')),constant("N/A")).as('age').select('name','fname','age')


I am not able to construct the above Gremlin query from the Java code. I am not getting any option to add as('age') just before the select('name','fname','age') step. And without the as step the correct answer is not returned.


The answer should be:

==>[name:marko,fname:vadas,age:27]
==>[name:marko,fname:josh,age:N/A]

As we are interested in finding the name, fname and age (age is optional here), so even if the value of age is not satisfied by the filter step or does not exist in general, all the possible answers (i.e. all people Marko knows) should be returned.

If I remove the as step, I get only one answer:

==>[name:marko,fname:vadas,age:27]

Why does this happen? Can you explain something about this?



Dharmen Punjani

unread,
Jul 20, 2018, 12:28:41 PM7/20/18
to Gremlin-users

Hello all one modification in above post from Harsh.

We are getting option to add as('age) just before select('name','fname','age') step. Even though we are not getting correct answer.

For above mentioned sparql we are having following gremlin traversal  for java code :

  [GraphStep(vertex,[]), MatchStep(AND,[[MatchStartStep(person), PropertiesStep([name],value), MatchEndStep(name)], [MatchStartStep(person), VertexStep(OUT,[knows],vertex), MatchEndStep(friend)], [MatchStartStep(friend), PropertiesStep([name],value), MatchEndStep(fname)]]), CoalesceStep([[MatchStep(AND,[[MatchStartStep(friend), PropertiesStep([age],value), MatchEndStep(age)], [MatchStartStep(age), WhereTraversalStep([WhereStartStep, IsStep(lte(30))]), MatchEndStep]]), ConstantStep(N/A)]])@[age], SelectStep([name, fname, age])]


and answer we are getting is 
 ==> {name=marko, fname=vadas, age=N/A}

But the correct answer is 
==>[name:marko,fname:vadas,age:27]
==>[name:marko,fname:josh,age:N/A]


Also if it is possible to have coalesce() giving correct answers without as() ? and if yes how ?  can anyone point to it?

Thanks a lot !!!

Daniel Kuppitz

unread,
Jul 20, 2018, 12:43:31 PM7/20/18
to gremli...@googlegroups.com
The following snippet returns just that:

final GraphTraversalSource g = TinkerFactory.createModern().traversal();
g.V().match(
__.as("person").hasLabel("person"),
        __.as("person").values("name").as("name"),
__.as("person").out("knows").as("friend"),
        __.as("friend").values("name").as("fname"))
.coalesce(
__.match(__.as("friend").values("age").is(P.lte(30)).as("age")),
(Traversal) __.constant("N/A")).as("age")
.select("name","fname","age")
.forEachRemaining(System.out::println);

Since the 2 child traversals of coalesce() have different return types, you have to cast at least one of them into a non-generic type.

Cheers,
Daniel

To unsubscribe from this group and stop receiving emails from it, send an email to gremlin-users+unsubscribe@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/gremlin-users/b0869f1a-1fa2-4791-a7f3-ec3907626cb1%40googlegroups.com.

Harsh Thakkar

unread,
Jul 20, 2018, 1:40:35 PM7/20/18
to Gremlin-users
Many thanks! Makes sense now.. 

Dharmen Punjani

unread,
Jul 20, 2018, 1:53:22 PM7/20/18
to Gremlin-users
Thanks Daniel. 
You r true Gremlin Guru !!!
:-)
Reply all
Reply to author
Forward
0 new messages