0

I'm struggling to write a gremlin query that compares the values of each edge of a given branch of my traversal to both each other and a provided value.

Here's an example - let's say I have the following hierarchy composed of Schools, Teams, and Athletes, any of which can be connected to a Uniform via a wears edge. And let's also say I record the creation date of every edge as a property in that edge called created. In any possible branch, like the one highlighted in blue, I need to query for maximum(wears.created, establishes.created, recruits.created) >= 2009.

enter image description here

How can I display every uniform an athlete ever wore since 2009 along with the date they began wearing it?

Sometimes that date is the year an Athlete was recruited onto a Team, sometimes it's the year a School established a Team, and other times it's whenever an individual Athlete, Team, or School began wearing a new Uniform.

I need a way to select the maximum creation date of all edges in a branch (like the one in blue above) and then also to compare that maximum to the provided date of 2009.

Something like this maybe? Is anything like this possible in gremlin??

g.V().hasLabel("Athlete").as("athlete").union(
    __.outE("wears").has("created", P.gte(2009)).as("when").by("created"),
    __.inE("recruits").as("r").by("created").outV().hasLabel("Team")
        .outE("wears").as("w").by("created")
        .select(max("r", "w")).as("when")
        .where("when", P.gte(2009))
    __.inE("recruits").as("r").by("created").outV().hasLabel("Team")
        .inE("establishes").as("e").by("created").outV().hasLabel("School")
        .outE("wears").as("w").by("created")
        .select(max("r", "e", "w")).as("when")
        .where("when", P.gte(2009))
).inV().hasLabel("Uniform").as("uniform")
.select("athlete", "uniform", "when")

<== Edit =================================================>

Adding a startup script to assist in testing as per the comment by Steven Mallette.

g.addV('School').property('id',1).property("name", "Duke").as('duke').
  addV('School').property('id',2).property("name", "UNC").as('unc').
  addV('Team').property('id',3).property("name", "Soccer").as('soccer').
  addV('Team').property('id',4).property("name", "Football").as('football').
  addV('Team').property('id',5).property("name", "Basketball").as('basketball').
  addV('Athlete').property('id',6).property("name", "Joe").as('joe').
  addV('Athlete').property('id',7).property("name", "Jane").as('jane').
  addV('Athlete').property('id',8).property("name", "Alice").as('alice').
  addV('Athlete').property('id',9).property("name", "Bob").as('bob').
  addV('Uniform').property('id',10).property("color", "red").as('red').
  addV('Uniform').property('id',11).property("color", "pink").as('pink').
  addV('Uniform').property('id',12).property("color", "blue").as('blue').
  addV('Uniform').property('id',13).property("color", "teal").as('teal').
  addV('Uniform').property('id',14).property("color", "green").as('green').
  addE('contains').property("created", 2009).from('duke').to('soccer').
  addE('contains').property("created", 1960).from('unc').to('football').
  addE('contains').property("created", 2007).from('duke').to('basketball').
  addE('contains').property("created", 2016).from('soccer').to('bob').
  addE('contains').property("created", 2008).from('basketball').to('jane').
  addE('contains').property("created", 2010).from('basketball').to('alice').
  addE('contains').property("created", 2015).from('football').to('joe').
  addE('wears').property("created", 2009).from('duke').to('blue').
  addE('wears').property("created", 1999).from('unc').to('red').
  addE('wears').property("created", 2010).from('soccer').to('teal').
  addE('wears').property("created", 2009).from('football').to('pink').
  addE('wears').property("created", 2009).from('basketball').to('teal').
  addE('wears').property("created", 2012).from('alice').to('green')

With the expected output being the following (Adding the output per Daniel Kuppitz's suggestion). To explain the first line of the output: Jane wears teal since 2009 because the basketball team formed in 2007 at duke, Jane joined the team in 2008, but the basketball team started wearing teal in 2009, so 2009 is the maximum date for Jane and this Uniform.

Jane wears teal since 2009
Jane wears blue since 2009
Alice wears teal since 2010
Alice wears blue since 2010
Alice wears green since 2012
Joe wears pink since 2015
Joe wears red since 2015
Bob wears blue since 2016
Bob wears teal since 2016
SnoopDougg
  • 1,467
  • 2
  • 19
  • 35
  • Could you please provide a Gremlin script that creates some sample data - here is an example https://stackoverflow.com/questions/51388315/gremlin-choose-one-item-at-random – stephen mallette Jan 07 '19 at 19:56
  • @stephenmallette yah definitely, I've edited my question to provide a script at the bottom. – SnoopDougg Jan 07 '19 at 20:26

1 Answers1

1

Hopefully the final edit after the most recent comments (but the result now matches your expected result, so I think we're good):

gremlin> g.V().hasLabel("Athlete").as("a").
           union(outE("wears").sack(assign).by("created"),
                 inE("contains").sack(assign).by("created").outV().
                 union(outE("wears").sack(max).by("created"),
                       inE("contains").sack(max).by("created").outV().
                       outE("wears").sack(max).by("created"))).
           filter(sack().is(gte(2009))).
           project("athlete","when","uniform").
             by(select("a").by("name")).
             by(sack()).
             by(inV().values("color"))
==>[athlete:Joe,when:2015,uniform:pink]
==>[athlete:Joe,when:2015,uniform:red]
==>[athlete:Jane,when:2009,uniform:teal]
==>[athlete:Jane,when:2009,uniform:blue]
==>[athlete:Alice,when:2012,uniform:green]
==>[athlete:Alice,when:2010,uniform:teal]
==>[athlete:Alice,when:2010,uniform:blue]
==>[athlete:Bob,when:2016,uniform:teal]
==>[athlete:Bob,when:2016,uniform:blue]

Or, since your schema is pretty uniform, you can actually use repeat() and thus get rid of the unreadable nested union()'s:

gremlin> g.withSack(0).V().hasLabel("Athlete").as("a").
           emit().
             repeat(inE("contains").sack(max).by("created").outV()).
             times(2).
           outE("wears").sack(max).by("created").
           filter(sack().is(gte(2009))).
           project("athlete","when","uniform").
             by(select("a").by("name")).
             by(sack()).
             by(inV().values("color"))
==>[athlete:Joe,when:2015,uniform:pink]
==>[athlete:Joe,when:2015,uniform:red]
==>[athlete:Jane,when:2009,uniform:teal]
==>[athlete:Jane,when:2009,uniform:blue]
==>[athlete:Alice,when:2012,uniform:green]
==>[athlete:Alice,when:2010,uniform:teal]
==>[athlete:Alice,when:2010,uniform:blue]
==>[athlete:Bob,when:2016,uniform:teal]
==>[athlete:Bob,when:2016,uniform:blue]
Daniel Kuppitz
  • 10,846
  • 1
  • 25
  • 34
  • Thanks Daniel Kuppitz, and sorry, I definitely should have included the expected results. I've edited my question to include them now. I'm having trouble getting your query to work in the Azure portal, but I'll try again via a groovy command line. Just out of curiosity, where does the "uniform" alias get set? – SnoopDougg Jan 08 '19 at 20:58
  • 1
    The project() step is responsible for all 3 keys. – Daniel Kuppitz Jan 08 '19 at 21:22
  • So you want all combinations that occurred after 2009? I thought you only want the latest (maximum creation date), but Alice is listed with 2010 and 2012 in your expected result, that's a little confusing. Besides that, there's actually no edge for Alice that matches the date 2010, I guess it should be 2009 (basketball team and Duke school). – Daniel Kuppitz Jan 08 '19 at 21:41
  • Ah, sorry, it was hard to put what I wanted into words much less a query, but yes I want all the combinations since 2009. But the maximum comes into play for each branch - for example, the reason Jane wears teal since 2009 is because the Basketball team formed in 2007 at Duke, Jane joined the team in 2008, but the Basketball team started wearing teal in 2009, so 2009 is the max date for Jane and this Uniform. Does that make sense? So Alice has worn teal since 2010 because she joined the basketball team in 2010 and the basketball team, established in 2007, has been wearing teal since 2009. – SnoopDougg Jan 08 '19 at 23:00
  • Yeah, I think I got it. Trying to put that into a query now. – Daniel Kuppitz Jan 09 '19 at 03:47
  • Oh damn, sorry for the delay, I think I must have missed the notification that you updated your answer. I'm having a little trouble getting the `sack` clause to work in Azure CosmosDB / the `org.apache.tinkerpop.gremlin-groovy:3.3.3` library, but I was able to run these just fine in my local gremlin console. Very cool, thanks! – SnoopDougg Jan 31 '19 at 22:13