问题描述
我正在尝试创建一个遍历,添加一个顶点,然后从已知顶点添加一条边到新顶点。我有 a library method 使用 coalesce
来检查是否存在现有边缘(它不可能),如果不存在则添加它。但是,我可靠地将边添加到第一个子顶点,然后没有边添加到新子顶点。这是遍历:
gts.addV()... // add properties and such; this part reliably works
.as('newV') // needed because I can't pass __addV() to the edge coalesce or I get two adds
.V(parent)
.coalesce(
__.outE('Manages').where(inV().has(id,__select('newV').id())).hasNot(TTL_END),__.addE('Manages').to(__select('newV')).property(TTL_START,Now)
)
当我分析这次遍历时,我发现添加第二个和后续子顶点时有些奇怪:
CoalesceStep([[VertexStep(OUT,[Manages],edge),... 1 1 0.469 18.82
VertexStep(OUT,edge) 1 1 0.020
TraversalFilterStep([EdgeVertexStep(IN),Prof... 1 1 0.188
EdgeVertexStep(IN) 1 1 0.010
TraversalFilterStep([IdStep,ProfileStep,S... 0.091
IdStep 1 1 0.010
SelectOnestep(last,newV) 1 1 0.020
NoOpBarrierStep(2500) 1 1 0.019
IdStep 0.012
NotStep([Propertiesstep([ttl.end],value),Pro... 1 1 0.170
Propertiesstep([ttl.end],value) 0.008
EdgeVertexStep(IN) 1 1 0.305 12.23
据我所知,这似乎是在说“id
过滤器”正在过滤掉不匹配的新孩子1,因此不返回任何遍历器(这就是我期望),但是随后 hasNot
步骤,我希望在接下来的管道中应用,弹出回到顶层,说“边缘(对第一个孩子)没有 {{1 }},所以我会归还它!”,ttl.end
接受了它,我没有把我的优势传给第二个孩子。
我的理解是,一旦遍历器“死亡”,额外的过滤步骤将被简单地作为多余的过滤步骤丢弃,并且不会通过遍历传播更多内容,但我期望作为 AND 过滤器的行为似乎是“复活”ID过滤器应该“杀死”的遍历器。
为什么 coalesce
会被遍历,即使它的上游过滤器不应该匹配?我怎样才能产生我想要的复合谓词?
(我也首先尝试了 NotStep
步骤,得到了相同的结果,步骤在配置文件输出中转置。)
1 第二个 `IdStep` 上根本没有任何遍历器是否表明存在问题?
解决方法
has(String,Traversal)
步骤可能是现存最被误用的步骤。用户期望它的意思是“将 Traversal
解析为一个值,并使该值与指定键进行相等比较”。但是,正如你所看到的,这不是它的作用:
gremlin> g = TinkerFactory.createModern().traversal()
==>graphtraversalsource[tinkergraph[vertices:6 edges:6],standard]
gremlin> g.V().as('a').has(id,select('a'))
==>v[1]
==>v[2]
==>v[3]
==>v[4]
==>v[5]
==>v[6]
文档试图用这个来解释它(也许还有其他地方的解释/例子):
has(key,traversal)
:如果遍历器的对象没有通过属性值的遍历产生结果,则移除遍历器。
因此,在该上下文中,如果您将 select()
用于 Traversal
参数,请考虑会发生什么 - 它有效地忽略了作为遍历器的“属性值”,并从 {{ 的任何返回值中插入它自己的值1}}。除非您选择不存在的内容,否则它会返回一个值,因此过滤器通过。我们已经讨论过更改此行为,但担心会破坏依赖此功能的现有代码。也许它在未来可能会改变......
说了这么多,我想我会按如下方式重写您的遍历:
select()
嵌套的 gremlin> g = TinkerGraph.open().traversal()
==>graphtraversalsource[tinkergraph[vertices:0 edges:0],standard]
gremlin> g.addV('person').property(id,'parent')
==>v[parent]
gremlin> now = 100
==>100
gremlin> g.addV('person').as('newV').
......1> V('parent').
......2> coalesce(
......3> __.outE('Manages').where(inV().where(eq('newV'))).hasNot("end"),......4> __.addE('Manages').to(__.select('newV')).property("start",now))
==>e[1][parent-Manages->0]
gremlin> g.addV('person').as('newV').
......1> V('parent').
......2> coalesce(
......3> __.outE('Manages').where(inV().where(eq('newV'))).hasNot("end"),now))
==>e[3][parent-Manages->2]
gremlin> g.E().property('end',101)
==>e[1][parent-Manages->0]
==>e[3][parent-Manages->2]
gremlin> g.addV('person').as('newV').
......1> V('parent').
......2> coalesce(
......3> __.outE('Manages').where(inV().where(eq('newV'))).hasNot("end"),now))
==>e[5][parent-Manages->4]
可能是表达此过滤器的更好方式。