在 gremlin 中,如何查找和排序给定顶点所属的所有连接顶点的三元组?

In gremlin, how to find and sort all triads of connected vertices that a given vertex belongs to?

我正在制作一个社交应用程序,用户可以在这里成为朋友。

对于给定的用户 A,我想找到满足 A -isFriends-> B AND B -isFriends-> C AND C -isFriends-> A.

的所有用户三元组

我目前的做法是:

g.V(A).repeat(__.out('isFriends')).times(3).path().by(id).toList()

然后在 gremlin 之外,我过滤掉第一个对象与最后一个对象不同的所有 Path 对象。我更希望让 gremlin 为我执行此过滤,但我不确定如何根据 path().

的输出进行过滤

我试过 cyclicPath(),但这只是 returns 顶点对象的平面列表,我不明白。由此我希望输出与 path() 类似,但只包含第一个和最后一个顶点相同的路径。如果这个期望不正确,请告诉我。

然后我还想根据子遍历的结果(三个顶点有多少共同朋友)对这些路径进行排序,但我不确定如何 运行 从path() 的输出中包含的顶点,无需启动新的 gremlin 查询。

我正在使用 javascript-gremlin 驱动程序 (v3.4.4) 并针对 AWS Neptune 进行查询,其中 lambda 不可用。

如果我的方法或理解有误,请告诉我。

所以我尝试为您的问题创建一个示例图表: sample graph

您正在尝试寻找一条简单的循环路径,我认为您可以通过以下方式实现:

g.V().hasLabel('A').as('a')
.both('isFriends').as('b')
.both('isFriends').as('c')
.where(both('isFriends').hasLabel('A'))
.select('a', 'b', 'c')

注意:三元组是对称的,因此每个元组都会 return 两次。

下面的查询可以回答您的两个问题。 优化 到 运行 只有 2 个跃点:

g.V().hasLabel("A").as("A").both("isFriends").as("B").aggregate("friends")
.out("isFriends").as("C").where(within("friends"))
.project("triad","mutual")
  .by(select("A","B","C").by(label()))
  .by(select("B","C").select(values).unfold()
    .both("isFriends").where(within("friends"))
    .groupCount().by().unfold()
    .where(select(values).is(eq(2)))
    .select(keys).label().fold())
.order().by(select("mutual").count(local), desc)

一些解释:

  • 找到 A 朋友并将他们存储为 'friends'。
  • 然后找到他们在 'friends' 内的朋友,从而与 A 成为朋友(这次使用 out 以防止重复)。
  • 使用项目使结果更详细。
  • 选择A、B、C得到三合会。

现在开始寻找黑社会共同朋友的有趣部分:

  • 从B和C开始,找到他们也是A朋友的朋友。
  • 对那些朋友进行分组计数,并仅过滤那些计数为 2 的朋友(同时拥有 B 和 C 的朋友)。
  • 最后,根据共同好友的数量对结果进行排序。

代替实际的共同好友列表,您可以通过替换最后两行只保留他们的数量:

    .select(keys).label().fold())
.order().by(select("mutual").count(local), desc)

与:

    .count())
.order().by(select("mutual"), desc)

最后,如果您只想要三元组(仍然排序),您可以删除项目:

g.V().hasLabel("A").as("A").both("isFriends").as("B").aggregate("friends")
.out("isFriends").as("C").where(within("friends"))
.order().by(
    select("B","C").select(values).unfold()
    .both("isFriends").where(within("friends"))
    .groupCount().by().unfold().where(select(values).is(eq(2)))    
    .count(), desc)
.select("A","B","C").by(label()).select(values)