0

我正在尝试创建一个遍历,该遍历添加一个顶点,然后将已知顶点的边添加到新顶点。我有一个库方法,用于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,[Manages],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我希望应用的步骤在接下来的管道中,弹出回到顶层,说“边缘(对第一个孩子)没有ttl.end,所以我会退回它!”,coalesce接受它,但我没有得到我的优势第二个孩子。

我的理解是,一旦遍历器“死亡”,额外的过滤步骤将被简单地丢弃为多余的,并且不会通过遍历传播更多内容,但我期望作为 AND 过滤器的行为似乎是“复活”遍历ID过滤器应该已经“杀死”。

为什么NotStep即使它的上游过滤器不应该匹配,也会被遍历?我怎样才能产生我想要的复合谓词?

(我也先尝试了这个hasNot步骤,我得到了相同的结果,在配置文件输出中转换了步骤。)


1在第二个“IdStep”上根本没有任何遍历器是否表明存在问题?
4

1 回答 1

1

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参数会发生什么 - 它实际上忽略了作为遍历器的“属性值”,并从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"),
......4>     __.addE('Manages').to(__.select('newV')).property("start", 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"),
......4>     __.addE('Manages').to(__.select('newV')).property("start", now))
==>e[5][parent-Manages->4]

嵌套where()可能是表达此过滤器的更好方式。

于 2021-02-02T18:14:35.883 回答