【问题标题】:In gremlin, how to find and sort all triads of connected vertices that a given vertex belongs to?在 gremlin 中,如何查找和排序给定顶点所属的所有连接顶点的三元组?
【发布时间】:2020-02-10 19:13:04
【问题描述】:

我正在制作一个用户可以成为朋友的社交应用。

对于给定的用户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(),但这只是返回一个顶点对象的平面列表,我不明白。由此我希望与path() 有类似的输出,但只包含第一个和最后一个顶点相同的路径。如果这个预期不正确,请告诉我。

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

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

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

【问题讨论】:

    标签: javascript gremlin amazon-neptune


    【解决方案1】:

    以下是回答您两个问题的查询。它已优化,只需 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 成为朋友(这次使用 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)
    

    【讨论】:

    • 哇,非常感谢。这非常有帮助。我有第一部分工作,我理解它。在第二部分,我不怀疑它是否有效,但我对某些步骤感到困惑。您能否发布一个修改后的查询,只保留计数而没有共同朋友的实际列表?这将帮助我了解在第二部分中为了什么目的正在执行哪些步骤。一旦我理解,肯定会接受,非常感谢您的时间和知识。
    • 我按要求添加了另外 2 个选项。寻找共同朋友的想法是从 B 和 C 都遍历到他们的朋友,只过滤那些也是 A 朋友的人,然后找到那些重复的人 (count=2) 以获得 B 和 C 的共同朋友。希望现在更清楚了。
    【解决方案2】:

    所以我尝试为您的问题创建一个示例图表: 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')
    

    注意:三元组是对称的,所以它们每个都会返回两次。

    【讨论】:

    • 感谢您的解决方案,这有效!不过,Kfir 的解决方案在我的测试数据上似乎快了两倍,并且包括共同朋友部分。关于对称性和重复性的好点。将来我肯定会使用 gremlify,这是一个很棒的想法和工具。
    猜你喜欢
    • 1970-01-01
    • 2018-07-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多