Filter Edge by Property

4,043 views
Skip to first unread message

Greg H

unread,
Aug 31, 2016, 11:02:00 AM8/31/16
to Gremlin-users
I'm wondering how to access edge properties within a filter, or if this is possible? 
Trying to do something like this.. 
g.V()
.repeat(inE().filter({ it.getProperty("foo").contains("search")}).subgraph('subGraph').outV())
.times(3)
.cap('subGraph')
.next()
Help appreciated. 

HadoopMarc

unread,
Sep 2, 2016, 3:16:29 AM9/2/16
to Gremlin-users
Hi Greg,

The makers discourage use of lambda steps, because they are not subject to execution optimization strategies. The gremlin step for filtering on properties is:
http://tinkerpop.apache.org/docs/current/reference/#has-step
so, you would get (not tested):
g.V()
.repeat(inE().has("foo", "search").subgraph('subGraph').outV())
.times(3)
.cap('subGraph')
.next()

I believe this should work if an edge has multiple ("foo", value) (key, value) pairs (not tested).
HTH,    Marc

Op woensdag 31 augustus 2016 17:02:00 UTC+2 schreef Greg H:

Greg H

unread,
Sep 2, 2016, 4:21:43 PM9/2/16
to Gremlin-users
Marc thx for the reply, but the TP3 docs indicate that only Vertexes can have multi-properties; that's why I am resorting to a filter to look for content within a single property. 

HadoopMarc

unread,
Sep 3, 2016, 2:12:15 PM9/3/16
to Gremlin-users
Hi Greg,

You´re right about the multi-properties. But then, the

has("foo", "search")

clause is what you were looking for? I am not sure what you want with the .contains("search"), I inerpreted is as the value of the "foo" property.

Cheers,    Marc

Op vrijdag 2 september 2016 22:21:43 UTC+2 schreef Greg H:

Greg H

unread,
Sep 3, 2016, 5:05:29 PM9/3/16
to Gremlin-users
Hi Marc

Yes I guess I should clarify that. 

Given the lack of multi-properties on an edge I was planning to just encode a list of properties into a single string. For example foo might have the value 'a b c'; and my traversal would look for the presence of some value within the property; that was the point of using a filter and a predicate on the property value.  I couldn't work out the syntax for doing so; not sure if it's possible? 

inE().filter({ it.getProperty("foo").contains("b")})

Thx,
Greg

HadoopMarc

unread,
Sep 4, 2016, 3:54:59 AM9/4/16
to Gremlin-users
Hi Greg,

OK, then your approach seems valid, so just eat your way through the javadoc:

gremlin> graph=TinkerFactory.createModern()
==>tinkergraph[vertices:6 edges:6]
gremlin> g=graph.traversal()
==>graphtraversalsource[tinkergraph[vertices:6 edges:6], standard]
gremlin> g.E()
==>e[7][1-knows->2]
==>e[8][1-knows->4]
==>e[9][1-created->3]
==>e[10][4-created->5]
==>e[11][4-created->3]
==>e[12][6-created->3]
gremlin> g.E().map{it -> it.getClass()}
==>class org.apache.tinkerpop.gremlin.process.traversal.traverser.O_Traverser
==>class org.apache.tinkerpop.gremlin.process.traversal.traverser.O_Traverser
==>class org.apache.tinkerpop.gremlin.process.traversal.traverser.O_Traverser
==>class org.apache.tinkerpop.gremlin.process.traversal.traverser.O_Traverser
==>class org.apache.tinkerpop.gremlin.process.traversal.traverser.O_Traverser
==>class org.apache.tinkerpop.gremlin.process.traversal.traverser.O_Traverser
gremlin> g.E().map{it -> it.get().getClass()}
==>class org.apache.tinkerpop.gremlin.tinkergraph.structure.TinkerEdge
==>class org.apache.tinkerpop.gremlin.tinkergraph.structure.TinkerEdge
==>class org.apache.tinkerpop.gremlin.tinkergraph.structure.TinkerEdge
==>class org.apache.tinkerpop.gremlin.tinkergraph.structure.TinkerEdge
==>class org.apache.tinkerpop.gremlin.tinkergraph.structure.TinkerEdge
==>class org.apache.tinkerpop.gremlin.tinkergraph.structure.TinkerEdge
gremlin> g.E().valueMap()
==>[weight:0.5]
==>[weight:1.0]
==>[weight:0.4]
==>[weight:1.0]
==>[weight:0.4]
==>[weight:0.2]
gremlin> g.E().map{it -> it.get().property("weight")}
==>p[weight->0.5]
==>p[weight->1.0]
==>p[weight->0.4]
==>p[weight->1.0]
==>p[weight->0.4]
==>p[weight->0.2]
gremlin> g.E().filter{it -> it.get().property("weight").value().toString().contains("1")}
==>e[8][1-knows->4]
==>e[10][4-created->5]

Cheers,      Marc

Op zaterdag 3 september 2016 23:05:29 UTC+2 schreef Greg H:

HadoopMarc

unread,
Sep 4, 2016, 10:57:30 AM9/4/16
to Gremlin-users
Some small addition. While edges cannot have multipe properties with the same key, like vertices can, they can have a list as property value:

gremlin> graph=TinkerFactory.createModern()
==>tinkergraph[vertices:6 edges:6]
gremlin
> g=graph.traversal()
==>graphtraversalsource[tinkergraph[vertices:6 edges:6], standard]

gremlin
> g.E().valueMap(true)
==>[label:knows, weight:0.5, id:7]
==>[label:knows, weight:1.0, id:8]
==>[label:created, weight:0.4, id:9]
==>[label:created, weight:1.0, id:10]
==>[label:created, weight:0.4, id:11]
==>[label:created, weight:0.2, id:12]
gremlin
> g.E(7).property("test", [1,2,3])

==>e[7][1-knows->2]

gremlin
> g.E(7).valueMap(true)
==>[label:knows, test:[1, 2, 3], weight:0.5, id:7]
gremlin
> test = g.E(7).valueMap(true).next()["test"]
gremlin> g.E(7).property("test", test + [4])

==>e[7][1-knows->2]

gremlin
> test = g.E(7).valueMap(true)
==>[label:knows, test:[1, 2, 3, 4], weight:0.5, id:7]





Op zondag 4 september 2016 09:54:59 UTC+2 schreef HadoopMarc:

Greg H

unread,
Sep 4, 2016, 6:21:40 PM9/4/16
to Gremlin-users
Ok THAT is sweet

I tried to write my queries using list properties initially and was told they weren't supported - but this also works on Vertices. Nice!

I can test the list via filter (below) but I can't find a way to test is within a has() step..  

gremlin> g.addV( "name","v1", "test", [1,2,3,"abc"])
==>v[0]
gremlin> g.V().valueMap()
==>[test:[[1, 2, 3, abc]], name:[v1]]
gremlin> g.V().has("test",1)
gremlin> g.V().has("test",[1])
gremlin> g.V().has("test",within(1))
gremlin> g.V().has("test",contains(1))

It does work in a filter though per your previous post :) 

gremlin> g.V().filter{it->it.get().property("test").value().contains(1)}
==>v[0]
gremlin> g.V().filter{it->it.get().property("test").value().contains(3)}
==>v[0]
gremlin> g.V().filter{it->it.get().property("test").value().contains("abc")}
==>v[0]

If you know of any way to access it in a has() step I'd love to know, otherwise thank you so much Marc - this helps me tremendously :) 

Cheers,
Greg

Robert Dale

unread,
Sep 4, 2016, 7:05:24 PM9/4/16
to gremli...@googlegroups.com
The predicates are operating on the top-level objects.  So, something like this would work where the lists are equal objects:

g.V().has("name","v1").has("test", [1,2,3,"abc"])

What you want is to inspect the contents of the list. You can create your own predicate that does this like so:

listContains = {x,y -> x.contains(y)}
g.V().has("name","v1").has("test", test(listContains,1))

Where test is a method of P.



--
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/32445c6f-a3dd-47b4-8da3-dce2f7c5952c%40googlegroups.com.
For more options, visit https://groups.google.com/d/optout.



--
Robert Dale

Greg H

unread,
Sep 5, 2016, 10:05:28 AM9/5/16
to Gremlin-users
Works like a charm - thank you Robert. 
To unsubscribe from this group and stop receiving emails from it, send an email to gremlin-user...@googlegroups.com.



--
Robert Dale

Greg H

unread,
Sep 5, 2016, 10:58:19 PM9/5/16
to Gremlin-users
Well at least it works like a charm in the Gremlin console, after providing the definition of listContains() there, but I can't get it to work in my JavaScript client no way no how, even after providing the definition there. 

I assume that I'll need to install this function at the gremlin server, and after looking through the docs and my server config console log I see that empty-sample.groovy is being loaded by my gremlin server at startup. I also see that it has an example of a function that goes into the global cache.

// An example of an initialization script that can be configured to run in Gremlin Server.
// Functions defined here will go into global cache and will not be removed from there
// unless there is a reset of the ScriptEngine.
def addItUp(x, y) { x + y } 

So I assume that I'll want to add something like this to empty-sample.groovy? 
def listContains(x,y) { x.contains(y) } 

Still, after restarting the gremlin server and the gremlin console I can't access listContains() from the console, or addItUp() for that matter either. 

gremlin> addItUp(1,2)
No signature of method: groovysh_evaluate.addItUp() is applicable for argument types: (java.lang.Integer, java.lang.Integer) values: [1, 2]
Display stack trace? [yN] 

I begin to understand why it's called Gremlin :-/

So the next question is how to install the a groovy function or possibly a predicate to the server so I can use it globally from my javascript gremlin-client? 

My setup is Titan1.0.0 Hadoop with cassandra+elasticsearch and a Gremlin 3.2 server. 

Help appreciated :) 

Robert Dale

unread,
Sep 6, 2016, 7:24:32 AM9/6/16
to gremli...@googlegroups.com
You're on the right path. Are you actually connecting to the gremlin server from the console?  The console may actually embed titan and gremlin executes locally.  You have multiple choices:

A) Always connect to the server and send remote commands. 

gremlin> :remote connect tinkerpop.server conf/remote.yaml
==>Configured localhost/127.0.0.1:8182
gremlin> :> addItUp(2,3)
==>5
gremlin> :> listContains([1,2,3],3)
==>true
gremlin> :> listContains([1,2,3],5)
==>false

B) Load your custom definitions in the console.

$ vi mydefs.groovy
$ ./bin/gremlin.sh mydefs.groovy 
gremlin> listContains([1,2,3],3)
==>true

C) All of the above.


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/c84c7912-038c-479b-8f79-b72d85c92ebe%40googlegroups.com.

For more options, visit https://groups.google.com/d/optout.



--
Robert Dale

Greg H

unread,
Sep 6, 2016, 9:32:27 AM9/6/16
to Gremlin-users
Thanks for the help Robert; not there yet but making progress.  

Taking the gremlin console out of the picture and focusing only on talking to the db via my javascript gremlin client, I have the following unit tests

it("4) can invoke predefined custom predicate", function(done) {
    client.execute('addItUp(2,3)',{}, function(err,result) {
      assert(result.length)
      assert(result[0]==5)
      done()
    })
})  // succeeds

it("5) can invoke my predefined custom predicate", function(done) {
    client.execute('listContains([1,2,3],3)',{}, function(err,result) {
      assert(!err)
      assert(result.length)
      assert(result[0]==true)
      done()
    })
})  // succeeds

it("6) can use has() with custom predicate", function(done) {
    client.execute('g.V().has("name","v1").has("read", test(listContains,"p3"))',{}, function(err,result) {
      console.log('6 returned err, result', err, result )
      assert(!err)
      assert(result)
      assert(result.length)
      done()
}) // fails with No such property: listContains for class: Script12 (Error 597)

The first two tests indicate that addItUp() and listContains() are in fact visible to the gremlin server at runtime, so my installation of the custom predicate should be at least in the right place and syntactically reasonabl, however the third test fails with the error 'No such property: listContains for class:Script12'. 

On a whim I tried rewriting the third test to treat listContains as a built-in predicate,

  it("6) can use has() with custom predicate", function(done) {
    client.execute('g.V().has("name","v1").has("read", listContains("p3"))',{}, function(err,result) {
      console.log('6 returned err, result', err, result )
      assert(!err)
      assert(result)
      assert(result.length)
      done()
    })
  })  // fails with No signature of method: Script1.listContains() is applicable for argument types: (java.lang.String) values.

This is a different error - it indicates that the signature of listContains() doesn't match the provided arguments. If I give it 2 arguments explicitly, ie 

  it("6) can use has() with custom predicate", function(done) {
    client.execute('g.V().has("name","v1").has("read", listContains([1,2,3],1))',{}, function(err,result) {
      console.log('6 returned err, result', err, result )
      assert(!err)
      assert(result)
      assert(result.length)
      done()
    })
  })  // fails with empty result (but no error!)

No errors this time - but also no results. It would appear that listContains was invoked, but it should have returned true and the query should have therefore produced a result. 

Anyway so the problem would seem to be with either the has step syntax or possibly my function definition?

def listContains(x,y) { x.contains(y) } 

My Setup is gremlin server 3.2 talking to Titan 1.0.0 

Help appreciated!





--
Robert Dale

Robert Dale

unread,
Sep 6, 2016, 10:08:38 AM9/6/16
to gremli...@googlegroups.com
Sorry, right, it will need to be defined as a closure, not as a function.  Try this under the globals initialization:

globals << [listContains : { x,y -> x.contains(y) }]



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/4f6b41c1-755d-4211-8ac4-6450c0a5a1a0%40googlegroups.com.

For more options, visit https://groups.google.com/d/optout.



--
Robert Dale

Greg H

unread,
Sep 6, 2016, 10:47:49 AM9/6/16
to Gremlin-users
Thanks Robert and sorry to occupy your time with this 

Unfortunately still no joy - same result. 

With listContains defined as:  globals << [listContains : { x,y -> x.contains(y) }]

If I use it as a predicate in a has() step I get the error no signature of method: Script1.listContains() is applicable for argument types: (java.lang.String) values: [p3], so it's receiving just one argument at runtime. 

 it("6) can use has() with custom predicate", function(done) {
    client.execute('g.V().has("name","v1").has("read", listContains("p3"))',{}, function(err,result) {
      console.log('6 returned err, result', err, result )
      assert(!err)
      assert(result)
      assert(result.length)
      done()
    })
  })  // fails with no signature of method: Script1.listContains() is applicable for argument types: (java.lang.String) values: [p3]


What's baffling is that if I call listContains with 2 arguments that should return true the query still doesn't return any results.

 it("6) can use has() with custom predicate", function(done) {
    client.execute('g.V().has("name","v1").has("read", listContains([1,2,3],1))',{}, function(err,result) {
      console.log('6 returned err, result', err, result )
      assert(!err)
      assert(result)
      assert(result.length)
      done()
    })
  })  // fails with no results

So I guess the question boils down to how to define and install custom predicates?

The manual mentions this is possible but doesn't elaborate :-/ 



--
Robert Dale

Robert Dale

unread,
Sep 6, 2016, 10:50:48 AM9/6/16
to gremli...@googlegroups.com
g.V().has("name","v1").has("read", test(listContains, "p3"))
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/50a423ee-d24a-48b6-8957-ce55ce52c7fa%40googlegroups.com.

For more options, visit https://groups.google.com/d/optout.



--
Robert Dale

Stephen Mallette

unread,
Sep 6, 2016, 10:51:09 AM9/6/16
to Gremlin-users
My setup is Titan1.0.0 Hadoop with cassandra+elasticsearch and a Gremlin 3.2 server. 

I haven' t been following this thread closely, but I'm somewhat surprised these two version work together at all. You may encounter some issues. Titan 1.0.0 is compatible with TinkerPop 3.0.x. To use TinkerPop 3.2.x you would need to build titan from source:


with:

mvn clean install -DskipTests=true -Paurelius-release -Dgpg.skip=true

that command will produce the zip distributions


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/50a423ee-d24a-48b6-8957-ce55ce52c7fa%40googlegroups.com.

Greg H

unread,
Sep 6, 2016, 11:00:36 AM9/6/16
to Gremlin-users
Right - that was your advice from the beginning - and it does in fact work with the expression defined as a closure. 

Thanks for the help Robert! 





--
Robert Dale

Greg H

unread,
Sep 6, 2016, 11:03:20 AM9/6/16
to Gremlin-users
I was also wondering if that might be a factor. They do appear to work but will take your advice and rebuild it. 

Thx,

Robert Dale

unread,
Sep 6, 2016, 11:30:13 AM9/6/16
to gremli...@googlegroups.com
You could take it one step further and create an actual predicate instead of using test.

globals << [listContains : { z -> new P({x,y -> x.contains(y)}, z) }]

g.V().has("name","v1").has("read", listContains("p3"))


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/c6aae2bb-5688-4107-8fc3-aa2466cf14ca%40googlegroups.com.

For more options, visit https://groups.google.com/d/optout.



--
Robert Dale

Greg H

unread,
Sep 6, 2016, 8:59:47 PM9/6/16
to Gremlin-users
Awesome - that was on my list but I didn't want to bother anyone for awhile. 

Thanks you've been a huge help :) 





--
Robert Dale
Reply all
Reply to author
Forward
0 new messages