不使用 Union 的具有可变边缘深度的 Gremlin 查询

Gremlin query with variable edge depth without using Union

我正在尝试组合一个 Gremlin 查询,该查询 returns 对某种边缘类型的 1 到 n 深度产生结果 - 不必求助于使用多个用 .union().

拼接在一起的查询

我有一些模拟销售办公室结构和在其中工作的人员的测试数据,包括谁管理哪些办公室以及哪些办公室“汇总”在哪些更高级别办公室的管辖下。下面的屏幕截图(实际上来自 Neo4j)显示了我要引用的图表的一个子集。

可以使用以下内容创建图表:

g.
addV('Office').as('O_111').property('code','111').
addV('Office').as('O_356').property('code','356').
addV('Office').as('O_279').property('code','279').
addV('Office').as('O_KC5').property('code','KC5').
addE('MERGES_INTO').from('O_356').to('O_111').
addE('MERGES_INTO').from('O_279').to('O_356').
addE('MERGES_INTO').from('O_KC5').to('O_279').
addV('Person').as('Bob').property('name','Bob').
  addE('MANAGES').from('Bob').to('O_111').addE('WORKS_WITH').from('Bob').to('O_111').
addV('Person').as('Michael').property('name','Michael').addE('WORKS_WITH').from('Michael').to('O_111').
addV('Person').as('John').property('name','John').addE('WORKS_WITH').from('John').to('O_111').
addV('Person').as('Rich').property('name','Rich').addE('WORKS_WITH').from('Rich').to('O_111').
addV('Person').as('Matt').property('name','Matt').
  addE('WORKS_WITH').from('Matt').to('O_279').addE('MANAGES').from('Matt').to('O_279').
addV('Person').as('Judy').property('name','Judy').addE('WORKS_WITH').from('Judy').to('O_279').
addV('Person').as('Joe').property('name','Joe'). addE('WORKS_WITH').from('Joe').to('O_279').
addV('Person').as('Ben').property('name','Ben').addE('WORKS_WITH').from('Ben').to('O_279').
addV('Person').as('Ron').property('name','Ron').addE('WORKS_WITH').from('Ron').to('O_KC5').

如果我想查看哪些人(橙色)在 Bob 直接或间接管理的办公室(粉红色)工作(因为,例如,办公室 KC5、279 和 356 汇总到 Bob 的 111 办公室),我可以使用 .union() 和类似下面的东西来获得正确的结果:

gremlin> g.V().has('Person','name','Bob').
......1>   out('MANAGES').
......2>   union(
......3>     __.in('WORKS_WITH'),
......4>     __.in('MERGES_INTO').in('WORKS_WITH'),
......5>     __.in('MERGES_INTO').in('MERGES_INTO').in('WORKS_WITH'),
......6>     __.in('MERGES_INTO').in('MERGES_INTO').in('MERGES_INTO').in('WORKS_WITH')
......7>     ).
......8>   values('name').fold()
==>[Bob, Michael, John, Rich, Matt, Judy, Joe, Ben, Ron]

这看起来超级冗长和笨拙。那是我唯一的选择吗?有没有更好的方法,不像.union()那样看起来那么多余?

来自 Neo4j 世界,我只是使用 *0.. 做一些深度为“0 或更多”的事情,像这样:

MATCH (manager:Person {name:'Bob'}) 
OPTIONAL MATCH (manager)-[:MANAGES]->(:Office)<-[:MERGES_INTO*0..]-(:Office)<-[:WORKS_WITH]-(p:Person)
RETURN p

我如何在 Gremlin 中实现同样的事情?即使我不能做开放式,但可以做 1 到某个任意限制(比如 1 到 10),那也行。这可能无关紧要,但我将使用 AWS Neptune 作为实际的 Graph 数据库。

在询问有关 Gremlin 的问题时,图表的图片很好,但提供一些示例数据的脚本更好 - 如下所示:

g.addV('person').property('name','michael').as('mi').
  addV('person').property('name','john').as('jo').
  addV('person').property('name','rich').as('ri').
  addV('person').property('name','bob').as('bo').
  addV('person').property('name','matt').as('ma').
  addV('person').property('name','ron').as('ro').
  addV('person').property('name','joe').as('joe').
  addV('person').property('name','ben').as('be').
  addV('person').property('name','judy').as('ju').
  addV('office').property('name','111').as('111').
  addV('office').property('name','356').as('356').
  addV('office').property('name','279').as('279').
  addV('office').property('name','kc5').as('kc5').
  addE('mergesInto').from('kc5').to('279').
  addE('mergesInto').from('279').to('356').
  addE('mergesInto').from('356').to('111').
  addE('worksWith').from('mi').to('111').
  addE('worksWith').from('jo').to('111').
  addE('worksWith').from('ri').to('111').
  addE('worksWith').from('bo').to('111').
  addE('manages').from('bo').to('111').
  addE('worksWith').from('ma').to('279').
  addE('manages').from('ma').to('279').
  addE('worksWith').from('joe').to('279').
  addE('worksWith').from('be').to('279').
  addE('worksWith').from('ju').to('279').
  addE('worksWith').from('ro').to('kc5').iterate()

您的直觉是正确的,但 union() 并不完全适合您想做的事情。我更喜欢 repeat():

gremlin> g.V().has('person','name','bob').
......1>   out('manages').
......2>   repeat(__.in('worksWith','mergesInto')).
......3>     emit(hasLabel('person')).
......4>   values('name')
==>bob
==>michael
==>john
==>rich
==>matt
==>joe
==>ben
==>judy
==>ron

通过这种方式,它遍历到任意深度(尽管我们倾向于建议设置某种合理的限制,以避免在 运行 某处出现意外循环时出现问题)并且更加简洁。请注意 emit() 的使用,它控制从 repeat() 编辑哪些类型的顶点 - 如果您不包括该过滤器,您也将 return “办公室”顶点。