匿名遍历 vs 普通遍历 Gremlin

5

我已阅读有关匿名遍历的文档。 我明白它们可以以__开头,并且可以在步骤调节器内使用。尽管我在概念上不理解。 为什么我们不能在步骤调节器内使用从图遍历源生成的普通遍历?例如,在以下Gremlin代码中创建边:

        this.g
            .V(fromId) // get vertex of id given for the source
            .as("fromVertex") // label as fromVertex to be accessed later
            .V(toId) // get  vertex of id given for destination
            .coalesce( // evaluates the provided traversals in order and returns the first traversal that emits at least one element
                inE(label) // check incoming edge of label given
                    .where( // conditional check to check if edge exists
                        outV() // get destination vertex of the edge to check
                            .as("fromVertex")), // against staged vertex
                addE(label) // add edge if not present
                    .property(T.id, id) // with given id
                    .from("fromVertex")) // from source vertexx
            .next(); // end traversal to commit to graph

为什么__.inE()__.addE()是匿名的?为什么不能写成this.g.inE()this.g.addE()呢?两种方式都不会引起编译器报错,那么使用匿名遍历在这里提供了什么特殊的优势呢?

好问题(解释得非常好)。 (同样由@stephen很好地回答了) - Kishore
1个回答

5
简而言之,在3.5.0版本中,用户无法使用从GraphTraversalSource生成的遍历,必须使用__,因此您可以期望在最新版本中看到这一点得到执行。
更加历史性地说,GraphTraversalSource(即g)旨在从具有分配源配置的起始步骤生成新的遍历。匿名遍历意味着在生成时“空白”,其内部配置应该采用其父遍历的内部配置。虽然可以覆盖从g生成的遍历的内部配置,但当分配给父级时,它并不总是能够按照设计工作的,因此依赖于该行为是有风险的。
另一个要点是,从Gremlin步骤的完整列表中,只有少数是实际的“起始步骤”(即addV()addE()inject()V()E()),因此在构建子遍历时,您实际上只能使用这些选项。由于通常需要访问完整的Gremlin步骤列表来启动子遍历参数,最好只使用__。通过遵循这个惯例保持一致性,可以防止在单个遍历中交替使用时出现“为什么子遍历有时以g开头,而其他时候以__开头”的混淆。

也许还有其他技术原因需要使用__。以下Gremlin Console片段演示了一个不需要大量解释就可以看到的简单原因:

gremlin> __.addV('person').steps[0].class
==>class org.apache.tinkerpop.gremlin.process.traversal.step.map.AddVertexStep
gremlin> g.addV('person').steps[0].class
==>class org.apache.tinkerpop.gremlin.process.traversal.step.map.AddVertexStartStep

两种遍历不会产生类似的步骤。如果今天使用 g 替换 __ 可以工作,那只是巧合而非设计,这意味着它将有可能在未来出现故障。

通过遍历源生成的遍历具有源的配置,而匿名生成的遍历继承父遍历的配置。我的理解正确吗?如果是这样,你能否举个例子来说明你所说的“配置”是什么?我看到这是两种遍历之间的主要区别。 - CHID
1
一个 GraphTraveralSource 通过其配置步骤获取配置 - 例如 withStrategies()withSideEffect() 等。 - stephen mallette
啊,我明白了。非常清楚。谢谢。使用匿名遍历来生成子遍历的原因是因为反复使用带有配置的源创建遍历是很昂贵的,这也是坚持使用匿名遍历的原因吗? - CHID
我不太确定那里是否存在需要考虑的性能方面。我建议不要过度专注于区分两者中的一个方面,而是将我写的所有内容整体考虑,以形成你的理解。 - stephen mallette

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接