Find all paths between two vertices
Not sure this makes any sense, but here goes. Could someone please provide a solution to how one would avoid dead-end paths to be traversed, i.e., how can one avoid multistep traversals following .bothE().otherV() to return to self?
Here's my non-working query
g.V().has('lbl', 'DexpiElement').has('tagname', 'tagA') \
.emit() \
.repeat( \
bothE().has('lbl', within('HAS_CHILD', 'HAS_CONNECTION', 'HAS_NODE', 'CONNECTED_TO', 'MAIN_CONNECTED_FROM', 'MAIN_CONNECTED_TO', 'HAS_GRAPHICS')).dedup().otherV().simplePath() \
) \
.until(has('lbl', 'DexpiElement').has('tagname', 'tagB')) \
.simplePath() \
.has('lbl', 'DexpiElementGraphic') \
.valueMap()
18 Replies
Hi, the problem comes from the emit step placed before the repeat step.
The emit step put the current traverser in the results (kind of) :
this works as intended :
g.addV('DexpiElement').property("tagname","tagA").as("a").
addV('DexpiElement').property("tagname","tagB").as("b").
addV('DexpiElement').property("tagname","tagC").as("c").
addV('DexpiElement').property("tagname","tagD").as("d").
addV('DexpiElement').property("tagname","tagE").as("e").
addV('DexpiElement').property("tagname","tagF").as("f").
addV('DexpiElement').property("tagname","tagG").as("g").
addV('DexpiElement').property("tagname","tagH").as("h").
addE("HAS_CHILD").from("a").to("c").
addE("HAS_CONNECTION").from("a").to("d").
addE("HAS_CHILD").from("d").to("e").
addE("HAS_CHILD").from("e").to("f").
addE("HAS_CHILD").from("f").to("g").
addE("HAS_CHILD").from("g").to("h").
addE("HAS_CHILD").from("h").to("b")
gremlin> g.V().hasLabel( 'DexpiElement').has('tagname', 'tagA').as("start").repeat( both('HAS_CHILD', 'HAS_CONNECTION', 'HAS_NODE', 'CONNECTED_TO', 'MAIN_CONNECTED_FROM','MAIN_CONNECTED_TO', 'HAS_GRAPHICS').dedup().simplePath()).until(hasLabel("DexpiElement").has('tagname', 'tagB')).path().by("tagname")
==>[tagA,tagD,tagE,tagF,tagG,tagH,tagB]
with the emit step before the repeat, you have all the path traversed :
gremlin> g.V().hasLabel( 'DexpiElement').has('tagname', 'tagA').as("start").emit().repeat( both('HAS_CHILD', 'HAS_CONNECTION', 'HAS_NODE', 'CONNECTED_TO', 'MAIN_CONNECTED_FROM','MAIN_CONNECTED_TO', 'HAS_GRAPHICS').dedup().simplePath()).until(hasLabel("DexpiElement").has('tagname', 'tagB')).path().by("tagname")
==>[tagA]
==>[tagA,tagC]
==>[tagA,tagD]
==>[tagA,tagD,tagE]
==>[tagA,tagD,tagE,tagF]
==>[tagA,tagD,tagE,tagF,tagG]
==>[tagA,tagD,tagE,tagF,tagG,tagH]
==>[tagA,tagD,tagE,tagF,tagG,tagH,tagB]
Perfect! Thanks a bunch
@flynnt_1337 a followup question - is there some way to access each DexpiElement of the resulting path, add their id's to a list for then to do further traversals?
got this far, but unsure how to do the within
g
.V().has('lbl', 'DexpiElement').has('tagname', 'A-20PSV0100')
.repeat(
bothE().has('lbl', within('HAS_CHILD', 'HAS_CONNECTION', 'HAS_NODE', 'CONNECTED_TO', 'MAIN_CONNECTED_FROM', 'MAIN_CONNECTED_TO')).dedup().otherV().simplePath()
)
.until(has('lbl', 'DexpiElement').has('tagname', 'A-20LV0011'))
.path()
.unfold()
.where(values('dexpi_id'))
.values('dexpi_id')
.fold()
.as('ids')
.V().has('lbl', 'DexpiElement').has('dexpi_id', within(select('ids')))
the path step can by modulated with a "by" step.
You can also unfold the path and have acces to the elements traversed (Vertex or Edges) :
g.V().hasLabel( 'DexpiElement').has('tagname', 'tagA').as("start").repeat( both('HAS_CHILD', 'HAS_CONNECTION', 'HAS_NODE', 'CONNECTED_TO', 'MAIN_CONNECTED_FROM','MAIN_CONNECTED_TO', 'HAS_GRAPHICS').dedup().simplePath()).until(hasLabel("DexpiElement").has('tagname', 'tagB')).path().unfold().valueMap()
==>[tagname:[tagA]]
==>[tagname:[tagD]]
==>[tagname:[tagE]]
==>[tagname:[tagF]]
==>[tagname:[tagG]]
==>[tagname:[tagH]]
==>[tagname:[tagB]]
Just be aware that in this case, the unfold will unfold all the path if there is more than one path found.
After the unfold step, you can continue your traversal like you want (with the value map in the exemple)
I get the strange part to it yes, unsure how to approach the query. What I'm aiming for is to get the path(s) between to vertices and then for each of the DexpiElements in this/these paths do do a further traversal off each of them to reach some child vertices
the " .where(values('dexpi_id'))
.values('dexpi_id')
.fold()
.as('ids')" is twisted.
What are you wanteing to do ?
so, you can just unfold after the path step
therefore I tried to collect the ids in a list to be used in a within statement
it will return the Vid, and you can follow the traversal
no need
It's already there
g.V().hasLabel( 'DexpiElement').has('tagname', 'tagA').as("start").repeat( both('HAS_CHILD', 'HAS_CONNECTION', 'HAS_NODE', 'CONNECTED_TO', 'MAIN_CONNECTED_FROM','MAIN_CONNECTED_TO', 'HAS_GRAPHICS').dedup().simplePath()).until(hasLabel("DexpiElement").has('tagname', 'tagB')).path().unfold()
==>v[0]
==>v[6]
==>v[8]
==>v[10]
==>v[12]
==>v[14]
==>v[2]
ok, got it - trying to get my head around how to interpret the outcomes of the different steps
(exemple with a TinkerGraph)
g.V().hasLabel( 'DexpiElement').has('tagname', 'tagA').as("start").repeat( both('HAS_CHILD', 'HAS_CONNECTION', 'HAS_NODE', 'CONNECTED_TO', 'MAIN_CONNECTED_FROM','MAIN_CONNECTED_TO', 'HAS_GRAPHICS').dedup().simplePath()).until(hasLabel("DexpiElement").has('tagname', 'tagB')).path().unfold().valueMap(true)
==>[id:0,label:DexpiElement,tagname:[tagA]]
==>[id:6,label:DexpiElement,tagname:[tagD]]
==>[id:8,label:DexpiElement,tagname:[tagE]]
==>[id:10,label:DexpiElement,tagname:[tagF]]
==>[id:12,label:DexpiElement,tagname:[tagG]]
==>[id:14,label:DexpiElement,tagname:[tagH]]
==>[id:2,label:DexpiElement,tagname:[tagB]]
the unfold to path results in both vertices and edges though, any way to filter only vertices to continue on, or again no need to?
you can filter the edges with a label filter.
I'm sure that your schema is well made and that edges and Vertex dosen't share labels.
wouldn't bet my life on it, but yes there's no sharing of labels between the two
g.V().hasLabel( 'DexpiElement').has('tagname', 'tagA').as("start").repeat( bothE('HAS_CHILD', 'HAS_CONNECTION', 'HAS_NODE', 'CONNECTED_TO', 'MAIN_CONNECTED_FROM','MAIN_CONNECTED_TO', 'HAS_GRAPHICS').otherV().dedup().simplePath()).until(hasLabel("DexpiElement").has('tagname', 'tagB')).path().unfold()
==>v[0]
==>e[17][0-HAS_CONNECTION->6]
==>v[6]
==>e[18][6-HAS_CHILD->8]
==>v[8]
==>e[19][8-HAS_CHILD->10]
==>v[10]
==>e[20][10-HAS_CHILD->12]
==>v[12]
==>e[21][12-HAS_CHILD->14]
==>v[14]
==>e[22][14-HAS_CHILD->2]
==>v[2]
gremlin> g.V().hasLabel( 'DexpiElement').has('tagname', 'tagA').as("start").repeat( bothE('HAS_CHILD', 'HAS_CONNECTION', 'HAS_NODE', 'CONNECTED_TO', 'MAIN_CONNECTED_FROM','MAIN_CONNECTED_TO', 'HAS_GRAPHICS').otherV().dedup().simplePath()).until(hasLabel("DexpiElement").has('tagname', 'tagB')).path().unfold().hasLabel("DexpiElement")
==>v[0]
==>v[6]
==>v[8]
==>v[10]
==>v[12]
==>v[14]
==>v[2]
This seems to be working
g.V().has('lbl', 'DexpiElement').has('tagname', 'tagA')
.repeat(
bothE().has('lbl', within('HAS_CHILD', 'HAS_CONNECTION', 'HAS_NODE', 'CONNECTED_TO', 'MAIN_CONNECTED_FROM', 'MAIN_CONNECTED_TO')).dedup().otherV().simplePath()
)
.until(has('lbl', 'DexpiElement').has('tagname', 'tagB'))
.path()
.unfold()
.has('lbl','DexpiElement')
.as('e')
.project('element', 'child')
.by(outE().has('lbl', 'HAS_GRAPHICS').inV().has('lbl', 'DexpiElementGraphic').as('eg').select('e','eg').by('dexpi_id').by(valueMap()).fold())
.by(outE().has('lbl', 'HAS_CHILD').inV().has('lbl', 'DexpiElement').as('ce').outE().has('lbl', 'HAS_GRAPHICS').inV().has('lbl', 'DexpiElementGraphic').as('cg').select('ce','cg').by('dexpi_id').by(valueMap()).fold())
but then again, likely not optimal in any measure
Anyways - thank you very much for helping out!
Glad i could help you
ahh, one last - you mentioned a potential issue with the first section returning multiple paths. any simple solution to that?
it was the emit step before the repeat that provoque that.
Emit pas the traverser to the next step. In your case,the traverser was emited without any filtering with the "has('lbl', 'DexpiElement').has('tagname', 'A-20LV0011')" that was used only to stop the repeat step.