如何使用Gremlin在Titan图数据库中查找团伙?

3

我需要使用Gremlin从我的图中找到所有大小为三的。在neo4j中,我可以使用Cypher完成此操作:

MATCH (a)-[:edge]-(b)-[:edge]-(c)-[:edge]-(a)
RETURN a,b,c

例子案例是:A->B->C->A
基于@pkohan的回答,一种可能的解决方案是:
g.V().as('x').sideEffect{x = it}.out().loop(1){it.loops < 4}{if(it.loops==4){if(it.object.id==x.id){true}else{false}}else{false}}.path.dedup().collect{"${it[0].id}->${it[1].id}->${it[2].id}"}

有人有其他的想法吗?

5
我认为这个问题不应该因为过于宽泛而被关闭。它是一个关于Cypher转换成Gremlin的相当具体的问题。下面的答案表明,对于熟悉Cypher和Gremlin图查询语言的人来说,这是可以理解的。 - stephen mallette
2个回答

2
我假设你正在使用Gremlin2。
gremlin> g = TinkerGraphFactory.createTinkerGraph()
==>tinkergraph[vertices:6 edges:6]
gremlin> g.V().as('x').both().loop('x') {it.loops < 3}.both().retain('x').path()
==>[v[1], v[3], v[4], v[1]]
==>[v[1], v[4], v[3], v[1]]
==>[v[3], v[4], v[1], v[3]]
==>[v[3], v[1], v[4], v[3]]
==>[v[4], v[1], v[3], v[4]]
==>[v[4], v[3], v[1], v[4]]

您可以看到,这是6个相同的团,只是起点和终点不同以及路径不同。以下是如何对结果集进行去重:

gremlin> g.V().as('x').both().except('x').loop('x') {it.loops < 3}.both().retain('x').path().transform {it[0..2].sort()}.dedup()
==>[v[1], v[3], v[4]]

由于您要查找的路径具有固定长度,因此您还可以摆脱循环结构(这应该会导致更快的执行):

gremlin> g.V().as('a').both().as('b').except('a').both().as('c').both().retain('a').path().transform {it[0..2].sort()}.dedup()
==>[v[1], v[3], v[4]]

在Gremlin3中,你几乎可以完成与Cypher相同的操作,但你也可以选择使用新的match-step来查找模式(如果你知道如何在Cypher中编写查询,则应该非常简单):

gremlin> graph = TinkerFactory.createModern()
==>tinkergraph[vertices:6 edges:6]
gremlin> g = graph.traversal(standard())
==>graphtraversalsource[tinkergraph[vertices:6 edges:6], standard]
gremlin> g.V().match("a",
gremlin>   __.as("a").both().as("b"),
gremlin>   __.as("b").both().as("c"),
gremlin>   __.as("c").both().as("d")).where("a", eq("d")).select("a", "b", "c").map {it.get().values().sort()}.dedup()
==>[v[1], v[3], v[4]]

2

以下是一个查询,对于大型图形来说效率极低,但可以实现您的预期:

g.V().filter{it.out().loop(1){it.loops < 3}.id.filter{i -> it.id == i}.hasNext()}.map

这会返回一个管道,其中包含可以在走完三条出边后指向自身的顶点。您可以通过更改闭包中的 it.loops < 3 来更改要遵循的边数。通过将 out() 更改为 in(),您可以执行传入边,或者使用 both() 进行任意方向的跟踪。您还可以通过将它们放在括号中缩小到特定类型的边,例如:

g.V().filter{it.out("EDGE_TYPE").loop(1){it.loops < 3}.id.filter{i -> it.id == i}.hasNext()}.map

我不确定neo4j是否有优化使得在大型数据库上可行,但我想在拥有数百万条边和顶点的titan图上运行此查询可能是危险的。


谢谢。你有没有想法如何返回每个找到的团的完整路径A->-B->C或A->-B->C->A? - crhistian
看起来你已经在上面解决了它,抱歉我应该仔细阅读一点! - pkohan

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