【问题标题】:Gremlin query works or not depending on the contextGremlin 查询是否有效取决于上下文
【发布时间】:2020-07-25 05:45:25
【问题描述】:

在查询中(由 stephen mallette 在this question 中编写),问题是在 gremlify 中有效,但是当我将其粘贴到我的项目中时会给出不正确的输出。

所以我打开 gremlify 来编写一个数据创建查询,然后将其粘贴到 gremlin 控制台中,以便在那里进行测试,我注意到如果在查询的数据创建部分之后执行它,它在 gremlify 中不起作用,并且据我了解,它应该可以工作。

查询是这样的:

g.V().as('a').
  repeat(both().simplePath()).
    times(2).
  where(both().as('a')).
  path().
  map(unfold().limit(3).order().by(id).dedup().fold())
  dedup().
  group('m').
    by(limit(local,2)).
  group('m').
    by(tail(local,2)).
  group('m').
    by(union(limit(local,1),tail(local,1)).fold()).     
  cap('m').
  unfold().
  map(select(values).unfold().unfold().order().by(id).dedup().fold()).
  dedup().
  map(unfold().values('name').fold())

这里有效,输出正确: https://gremlify.com/psiygozr559

这里它给出了一个不正确的输出: https://gremlify.com/mqw6ut0y1z (相同的图表,但使用查询创建)

这里它根本不提供任何输出: https://gremlify.com/fzgmzdq1omq (与之前相同,第 1 行有所变化)

在我的项目中也给出了不正确的输出,并且我没有像上面的 gremlify 项目那样在查询之前执行任何奇怪的操作。

还有另一个查询,我自己写的,效率较低,但在所有相同的情况下和我的项目中都能完美运行,请参阅:

https://gremlify.com/zihygx0w8e

https://gremlify.com/xsc6q8dranj

在我的项目中,我使用 Node.js 在本地连接到 gremlin 服务器,默认配置不变。

这里发生了一些我不明白的事情。

【问题讨论】:

    标签: gremlin tinkerpop tinkerpop3 gremlin-server


    【解决方案1】:

    通过扩展遍历,您扩展了Path。将addV('j') 放在遍历的前面会增加一些我原来的算法没有考虑到的东西:

    gremlin> g.addV("j").sideEffect(V().drop()).sideEffect(
    ......1>     addV("user").property("name", "luana").as("luana")
    ......2>     .addV("user").property("name", "luisa").as("luisa")
    ......3>     .addV("user").property("name", "sabrina").as("sabrina")
    ......4>     .addV("user").property("name", "marcello").as("marcello")
    ......5>     .addV("user").property("name", "mario").as("mario")
    ......6>     .addV("user").property("name", "lidia").as("lidia")
    ......7>     
    ......7>     .addE("friend").from("luana").to("luisa")
    ......8>     .addE("friend").from("luana").to("sabrina")
    ......9>     .addE("friend").from("luana").to("marcello")
    .....10>     .addE("friend").from("luana").to("mario")
    .....11>     .addE("friend").from("luana").to("lidia")
    .....12>     
    .....12>     .addE("friend").from("sabrina").to("luisa")
    .....13>     .addE("friend").from("sabrina").to("marcello")
    .....14>     .addE("friend").from("sabrina").to("mario")
    .....15>     
    .....15>     .addE("friend").from("mario").to("luisa")
    .....16>     .addE("friend").from("mario").to("marcello")
    .....17>     ).V().as('a').
    .....18>   repeat(both().simplePath()).
    .....19>     times(2).
    .....20>   where(both().as('a')).
    .....21>   path().by(label)
    ==>[j,user,user,user]
    ==>[j,user,user,user]
    ==>[j,user,user,user]
    ==>[j,user,user,user]
    ...
    ==>[j,user,user,user]
    

    您可以通过命名您关心的路径或以其他方式限制或过滤掉该初始路径元素来解释这一点:

    gremlin> g.addV("j").sideEffect(V().drop()).sideEffect(
    ......1>     addV("user").property("name", "luana").as("luana")
    ......2>     .addV("user").property("name", "luisa").as("luisa")
    ......3>     .addV("user").property("name", "sabrina").as("sabrina")
    ......4>     .addV("user").property("name", "marcello").as("marcello")
    ......5>     .addV("user").property("name", "mario").as("mario")
    ......6>     .addV("user").property("name", "lidia").as("lidia")
    ......7>     
    ......7>     .addE("friend").from("luana").to("luisa")
    ......8>     .addE("friend").from("luana").to("sabrina")
    ......9>     .addE("friend").from("luana").to("marcello")
    .....10>     .addE("friend").from("luana").to("mario")
    .....11>     .addE("friend").from("luana").to("lidia")
    .....12>     
    .....12>     .addE("friend").from("sabrina").to("luisa")
    .....13>     .addE("friend").from("sabrina").to("marcello")
    .....14>     .addE("friend").from("sabrina").to("mario")
    .....15>     
    .....15>     .addE("friend").from("mario").to("luisa")
    .....16>     .addE("friend").from("mario").to("marcello")
    .....17>     ).V().as('a').
    .....18>   repeat(both().simplePath()).
    .....19>     times(2).
    .....20>   where(both().as('a')).
    .....21>   path().from('a').
    .....22>   map(unfold().limit(3).order().by(id).dedup().fold()).
    .....23>   dedup().
    .....24>   group('m').
    .....25>     by(limit(local,2)).
    .....26>   group('m').
    .....27>     by(tail(local,2)).
    .....28>   group('m').
    .....29>     by(union(limit(local,1),tail(local,1)).fold()).     
    .....30>   cap('m').
    .....31>   unfold().
    .....32>   map(select(values).unfold().unfold().order().by(id).dedup().fold()).
    .....33>   dedup().
    .....34>   map(unfold().values('name').fold())
    ==>[luana,luisa,sabrina,mario]
    ==>[luana,sabrina,marcello,mario]
    ==>[luana,luisa,sabrina,marcello,mario]
    

    请注意上面的第 21 行,我们只需添加 path().from('a'),即从步骤标签“a”开始路径,然后查询再次开始工作。

    关于不使用sideEffect() 添加示例图形数据的其他示例,请注意path() 的输出,当它跟随repeat() 时:

    gremlin> g.addV("j").sideEffect(V().drop()).
    ......1>   addV("user").property("name", "luana").as("luana").
    ......2>   addV("user").property("name", "luisa").as("luisa").
    ......3>   addV("user").property("name", "sabrina").as("sabrina").
    ......4>   addV("user").property("name", "marcello").as("marcello").
    ......5>   addV("user").property("name", "mario").as("mario").
    ......6>   addV("user").property("name", "lidia").as("lidia").
    ......7>     
    ......7>   addE("friend").from("luana").to("luisa").
    ......8>   addE("friend").from("luana").to("sabrina").
    ......9>   addE("friend").from("luana").to("marcello").
    .....10>   addE("friend").from("luana").to("mario").
    .....11>   addE("friend").from("luana").to("lidia").
    .....12>     
    .....12>   addE("friend").from("sabrina").to("luisa").
    .....13>   addE("friend").from("sabrina").to("marcello").
    .....14>   addE("friend").from("sabrina").to("mario").
    .....15>     
    .....15>   addE("friend").from("mario").to("luisa").
    .....16>   addE("friend").from("mario").to("marcello").
    .....17>   V().as('a').both().path()
    ==>[v[712],v[713],v[715],v[717],v[719],v[721],v[723],e[725][713-friend->715],e[726][713-friend->717],e[727][713-friend->719],e[728][713-friend->721],e[729][713-friend->723],e[730][717-friend->715],e[731][717-friend->719],e[732][717-friend->721],e[733][721-friend->715],e[734][721-friend->719],v[721],v[715]]
    ==>[v[712],v[713],v[715],v[717],v[719],v[721],v[723],e[725][713-friend->715],e[726][713-friend->717],e[727][713-friend->719],e[728][713-friend->721],e[729][713-friend->723],e[730][717-friend->715],e[731][717-friend->719],e[732][717-friend->721],e[733][721-friend->715],e[734][721-friend->719],v[721],v[719]]
    ...
    ==>[v[712],v[713],v[715],v[717],v[719],v[721],v[723],e[725][713-friend->715],e[726][713-friend->717],e[727][713-friend->719],e[728][713-friend->721],e[729][713-friend->723],e[730][717-friend->715],e[731][717-friend->719],e[732][717-friend->721],e[733][721-friend->715],e[734][721-friend->719],v[719],v[721]]
    

    当您在sideEffect() 之外添加顶点/边时,它们会包含在该输出中。因此,当您尝试遍历V().as('a') 时,simplePath() 会立即将它们过滤掉!

    ==>[v[712],v[713],v[715],v[717],v[719],v[721],v[723],e[725][713-friend->715],e[726][713-friend->717],e[727][713-friend->719],e[728][713-friend->721],e[729][713-friend->723],e[730][717-friend->715],e[731][717-friend->719],e[732][717-friend->721],e[733][721-friend->715],e[734][721-friend->719],v[721],v[715]]
    

    查看v[721] 如何出现两次 - 一次用于addV(),一次用于V()simplePath() 看到你遍历了那个顶点并返回到它。

    我调试这个的方法(因为答案不是很清楚)是首先profile() 两次遍历并比较类似部分的计数。我注意到他们开始不同的地方,这让我很清楚问题开始的地方。从那里我开始并排执行查询直到这些步骤,直到我注意到Path 周围的输出差异。您可以了解一下如何分离和调试 Gremlin 查询 here

    【讨论】:

    • 我发布的一个问题仍然没有通过添加 from('a') 得到解决,这个问题:gremlify.com/uoqttm3rg5p 我通过删除 simplePath() 来修复它,因为我注意到在 simplePath() 之后没有返回任何内容。我不知道为什么会出现这个问题。也许你可以给我一些关于这方面的信息。
    • 通过在那些addV()addE() 调用中不产生副作用,您在路径上放置了更多对象。这些新添加的顶点将立即在第一个both()simplePath() 上显示一个循环将它们过滤掉。如果在最后一个addE()之后添加这个,你可以看到效果:V().as('a').both().path()
    • 对不起,我还是不明白。据我了解,使用 V() 选择图形的所有顶点与选择这些顶点相同,因为我使用 addV() 创建它们。为什么 simplePath() 的行为方式会根据顶点的选择方式而有所不同?
    • 我已经更新了我的答案,并解释了我要求您使用V().as('a').both().path() 尝试的内容 - 希望现在有意义。 Path 不仅仅是您遍历的 V() - 它是 Gremlin 遍历的所有元素,包括突变、转换等。
    • 你想的没错。 simplePath() 会过滤步骤的结果。在我的示例中,path() 的结果包括由addV() 步骤创建的所有顶点,因此当您使用V() 遍历所有顶点时,您会立即创建一个循环并simplePath() 过滤掉该特定路径。它将对您遍历的所有路径执行此操作,因为始终存在由addV() 创建的图中每个顶点的完整列表,然后是从V() 遍历的那些顶点之一。再看一下这个例子,发现每个Path 对象不止一次看到一个顶点。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-12-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-02-01
    • 1970-01-01
    相关资源
    最近更新 更多