【问题标题】:Why does my Gremlin migration query only add one edge from each vertex?为什么我的 Gremlin 迁移查询只从每个顶点添加一条边?
【发布时间】:2021-09-30 20:14:15
【问题描述】:

我正在尝试为尚未存在的每个 [Org-Manages->User] 添加一个Subscription 顶点([Org-Sends->Subscription

g.V().hasLabel('Org')
  .match(
    __.as('oV').out('Manages').as('uV'),
    not(__.as('oV').out('Sends').in('Receives').as('uV')
  )

我得到一组带有相关顶点对的元组oV,uV。到目前为止,一切顺利。

然后我附加了这个:

.sideEffect(
  addV('Subscription').as('newV')
    .select('oV').addE('Sends').to(select('newV'))
    .select('uV').addE('Receives').to(select('newV'))
)

我希望为每一对oV,uV 设置相关的结构。而是创建所有订阅顶点,并创建所有接收边,但每个组织只创建一个发送边

据我所知,sideEffect 的“输入”是一组“行”,其中包含许多重复的 Org 顶点。我还尝试在sideEffect 之前插入select('oV', 'uV'),而行为没有改变。 为什么addE,但只有addE,在看到特定的oV 后会短路?


我正在对 Amazon Neptune 执行此操作,并在控制台中运行 explain。这是我得到的解释,似乎与我的书面遍历相符:

Final Traversal[
    NeptuneGraphQueryStep(Vertex),
    NeptuneTraverserConverterStep,
    MatchStep(
        AND,[
            [MatchStartStep(oV), VertexStep(OUT,[Manages],vertex), MatchEndStep(uV)],
            [MatchStartStep(oV), WhereTraversalStep([NotStep([WhereStartStep, VertexStep(OUT,[Sends],vertex), VertexStep(IN,[Receives],vertex), WhereEndStep(uV)])]), MatchEndStep, MatchEndStep]
        ]
    ),
    TraversalSideEffectStep([
        AddVertexStep({$migration=[asdf], label=[Subscription]})@[newV],
        SelectOneStep(last,oV),
        NoOpBarrierStep(2500),
        AddEdgeStep({~to=[[SelectOneStep(last,newV)]], label=[Sends]}),
        SelectOneStep(last,uV),
        NoOpBarrierStep(2500),
        AddEdgeStep({~to=[[SelectOneStep(last,newV)]], label=[Receives]})
    ])
]

【问题讨论】:

  • 我做了很多实验(如下所示),但无法重现我相信您所描述的内容。也许你可以看看我的回答,看看我是否遗漏了一些细微差别,这会使我的实验与众不同。
  • 谢谢@KelvinLawrence,明天我会去看看。生产查询更复杂,但只能通过附加属性,我用match-part 确认sideEffect 的输入实际上返回了所有预期的展开对。

标签: java groovy gremlin tinkerpop amazon-neptune


【解决方案1】:

使用航线数据集,我尝试使用 Amazon Neptune 和 TinkerGraph 模拟您的查询。在每种情况下,一切似乎都按预期工作。我得到了我希望被创造的所有优势。这是我用来测试的。

航线数据集包括没有匹配返回的航线。所以我用其中一些来模拟我们想要创建一些边缘的地方。

gremlin> g.V().has('airport','region','GB-ENG').
......1>   match(__.as('a').out('route').as('b'),
......2>         __.not(__.as('b').out('route').as('a'))).
......3>   select('a','b').by('code')
==>[a:MAN,b:ANU]
==>[a:LTN,b:ORY]  

使用该基础,我添加了您的sideEffect 步骤。请注意,我在下面删除的查询中的 addE 步骤之间有一个不需要的逗号。

gremlin> g.V().has('airport','region','GB-ENG').
......1>   match(__.as('a').out('route').as('b'),
......2>         __.not(__.as('b').out('route').as('a'))).
......3>   sideEffect(addV('Subscription').as('newV').
......4>              select('a').addE('Sends').to(select('newV')).
......5>              select('b').addE('Receives').to(select('newV')))

==>[a:v[84],b:v[219]]
==>[a:v[206],b:v[107]]

然后我们可以验证所有预期的结构都已创建。

gremlin> g.V().hasLabel('Subscription')
==>v[61367]
==>v[61370]


gremlin> g.V().hasLabel('Subscription').inE().outV().path()
==>[v[61367],e[61369][219-Receives->61367],v[219]]
==>[v[61367],e[61368][84-Sends->61367],v[84]]
==>[v[61370],e[61372][107-Receives->61370],v[107]]
==>[v[61370],e[61371][206-Sends->61370],v[206]]  

请注意,可以使用where 步骤在不使用match 的情况下重写查询,这可能会产生更有效的查询执行计划。

gremlin> g.V().has('airport','region','GB-ENG').as('a').
......1>       out('route').as('b').
......2>       where(__.not(out('route').as('a'))).
......3>       select('a','b').
......4>       by('code')
==>[a:MAN,b:ANU]
==>[a:LTN,b:ORY] 

【讨论】:

  • 感谢您发现虚假逗号;这是一个张贴错误在这里。我注意到在您的示例中,遍历是往返于同一类型的顶点(机场),并且它没有正在遍历的中间顶点。关于折叠到 where 的选项当然是正确的,但这是针对一次性迁移的,使用 match 语法的审阅者可以更清楚地阅读逻辑。
猜你喜欢
  • 2021-04-29
  • 2018-02-11
  • 2015-07-06
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-01-14
  • 2022-01-06
相关资源
最近更新 更多