为何Gremlin查询在Gremlify与Neptune上结果不一致?
合并顶点及边属性的Gremlin查询在Gremlify与Neptune中结果不一致的原因
测试数据
g.addV("TopVertex").property('id', 4713).property('testProperty1','testProperty1').as('vertex1') .addV("SubVertex").property('name','C1').as('C1') .addV("SubVertex").property('name','C2').as('C2') .addV("SubVertex").property('name','C3').as('C3') .addE("splitsInto").from('vertex1').to('C1').property('ordinal',1) .addE("splitsInto").from('vertex1').to('C2').property('ordinal',2) .addE("splitsInto").from('vertex1').to('C3').property('ordinal',3) .addV("TopVertex").property('id', 4713).property('testProperty2','testProperty2').as('vertex2') .addV("SubVertex").property('name','C4').as('C4') .addV("SubVertex").property('name','C5').as('C5') .addV("SubVertex").property('name','C6').as('C6') .addE("splitsInto").from('vertex2').to('C4').property('ordinal',4) .addE("splitsInto").from('vertex2').to('C5').property('ordinal',5) .addE("splitsInto").from('vertex2').to('C6').property('ordinal',6)
现有解决方案
g.addV("MergedVertex").property('id', 4713).as('mergedVertex'). V().hasLabel("TopVertex").has('id', 4713).as('oldVertices'). outE().as('oldEdges'). inV().as('inVertices'). select('mergedVertex'). addE('splitsInto').to('inVertices').as('newEdges'). sideEffect(select('oldEdges').properties(). unfold().as('props'). select('newEdges'). property(select('props').key(), select('props').value())). select('oldVertices').drop()
问题描述
上述查询在Gremlify中执行正常,能完整复制所有边的ordinal属性;但在Neptune 1.1.1.0版本中,仅保留了两个原顶点的第一条边属性(ordinal 1和ordinal 4),其余边的属性全部丢失。
原因分析
Neptune 1.1.1.0属于较旧的引擎版本,对Gremlin遍历的作用域绑定逻辑处理与Gremlify使用的最新TinkerPop实现存在差异:
- 原查询嵌套的
sideEffect内,unfold()遍历旧边属性时,select('newEdges')没有正确关联到当前迭代生成的新边实例,而是复用了第一个创建的新边引用。 - 这导致后续所有旧边的属性都被重复设置到第一条新边上,其余新边完全没有获得属性复制。
修复方案
方案1:直接指定属性复制(针对已知属性)
如果边属性是明确已知的(如ordinal),可以直接在创建新边时指定属性值,避免嵌套sideEffect的作用域问题:
g.addV("MergedVertex").property('id', 4713).as('mergedVertex'). V().hasLabel("TopVertex").has('id', 4713).as('oldVertices'). outE().as('oldEdges'). inV().as('inVertices'). select('mergedVertex'). addE('splitsInto').to('inVertices'). property('ordinal', select('oldEdges').values('ordinal')). select('oldVertices').drop()
方案2:通用多属性复制(兼容任意边属性)
如果需要复制任意数量的边属性,可以调整sideEffect的嵌套结构,确保属性遍历与新边实例正确绑定:
g.addV("MergedVertex").property('id', 4713).as('mergedVertex'). V().hasLabel("TopVertex").has('id', 4713).as('oldVertices'). outE().as('oldEdges'). inV().as('inVertices'). select('mergedVertex'). addE('splitsInto').to('inVertices').as('newEdges'). sideEffect( select('oldEdges').properties().fold().as('edgeProps'). select('newEdges'). sideEffect( unfold('edgeProps').as('p'). property(select('p').key(), select('p').value()) ) ). select('oldVertices').drop()
方案3:升级Neptune引擎版本
Neptune在后续版本(如1.2.x及以上)中修复了这类Gremlin遍历作用域的兼容性问题,升级引擎版本后原查询即可正常执行。
内容的提问来源于stack exchange,提问作者r3dup
相关产品推荐
相关产品推荐

