Gremlin 小精灵:调用fold()或count()后无法返回上一步
此查询不返回任何内容,因为调用fold()将删除所有先前存储的as(): 当然,我总是可以以牺牲性能为代价来解决此类问题,通过搜索两次来重复成本,我正在寻找比这更好的解决方案 用store()替换as()也会产生不同的输出,因此这也不是解决方案。store()保留到fold(),但使用相同的字符串多次调用会将每个调用添加到列表中,as()将第一个调用替换为第二个调用,而不是使用相同的工具 你可以自己试试: 编辑: 更接近我真实查询的示例如下:Gremlin 小精灵:调用fold()或count()后无法返回上一步,gremlin,tinkerpop,tinkerpop3,gremlin-server,Gremlin,Tinkerpop,Tinkerpop3,Gremlin Server,此查询不返回任何内容,因为调用fold()将删除所有先前存储的as(): 当然,我总是可以以牺牲性能为代价来解决此类问题,通过搜索两次来重复成本,我正在寻找比这更好的解决方案 用store()替换as()也会产生不同的输出,因此这也不是解决方案。store()保留到fold(),但使用相同的字符串多次调用会将每个调用添加到列表中,as()将第一个调用替换为第二个调用,而不是使用相同的工具 你可以自己试试: 编辑: 更接近我真实查询的示例如下: g.V() .hasLabel('user') .p
g.V()
.hasLabel('user')
.project("u")
.by(
as("appUser")
.both("friend")
.project("result")
.by(
as("appUserFriend")
.choose(
both("friend").where(bothE('friend').where(bothV().as('appUser'))).count().is(lt(2)),
constant("too small").fold(),
union(
both("friend").where(bothE('friend').where(bothV().as('appUser'))),
select("appUserFriend")
).order().by("name").values("name").fold()
)
).select(values).unfold()
).select(values).unfold().dedup()
此查询查找所有可能的“朋友组”。要组成一组朋友,每个成员必须是至少两个其他朋友用户的朋友(至少一个三角形)。该查询可以工作,但也会生成总共有2个成员的组,即当不满足2个朋友的条件时,这些组将被忽略,因为“太小”
您可以在此处运行查询:
查询运行,输出正确,但请注意第11行和第14行(在gremlify中)中的搜索是相同的,为了提高性能,我想调用select()返回,而不是编写相同的搜索,但由于这个问题,这是不可能的。任何其他不写两次相同搜索的技巧都是受欢迎的
以下是对其工作原理的逐步说明:
考虑到你写问题的方式,我假设你并不真的关心“太小”的群体,这个问题是关于你在最后的步骤枚举中描述的算法。考虑到这个假设,我注意到你基本上是在检测三角形,然后尝试将它们相应地分组。周期检测在Gremlin配方中进行了讨论,模式基本上是:
g.V().as("a").repeat(both().simplePath()).times(2).where(both().as("a")).path()
或者删除了重复的路径:
g.V().as("a").repeat(both().simplePath()).times(2).where(both().as("a")).path().
dedup().by(unfold().order().by(id).dedup().fold())
以此为基础,您只需将这些结果转换为您正在寻找的组。如果您觉得在Gremlin之外的应用程序代码中这样做更有效,那么您可能会在Gremlin之外的应用程序代码中这样做,但使用Gremlin的一种方法是将三角形中的所有对分组,然后将分组的路径的元素组合在一起:
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())
也许还有更好的方法,但我认为这个查询至少可以避免您一次又一次地查询相同的路径。我还认为它更容易理解,因为一旦读者注意到三角形计数模式,其余的就是三角形计数模式和很多层次结构。很想知道在Gremlin或应用程序代码中是否更好地处理三角形分组处理。这可能值得探索
我不确定您的图形有多大,但这个特定的查询可能更适合使用Spark和a进行OLAP风格的处理,可能类似于。查询不需要选择()步骤,在创建组时不需要检查组大小,稍后可以使用where()完成创建所有组时的步骤:
g.V()
.hasLabel('user')
.project("userGroups")
.by(
as("appUser")
.both("friend")
.project("group")
.by(
union(
both('friend').where(neq('appUser')).where(both('friend').where(eq('appUser'))),
identity(),
select("appUser")
).order().by("name").values("name").fold()
).select(values).fold()
).select(values)
.repeat(unfold()).times(3)
// Here the groups of 2 members are removed:
.where(count(local).is(gt(2)))
.dedup()
路径历史记录在减少步骤(如
fold()
)后丢失,因此通常必须重新编写遍历以避免这种情况。在这种情况下,我不确定如何最好地建议如何重新编写它,因为这个示例感觉有点做作。结果应该是什么?“对于每个用户,如果有多个顶点,则返回该用户,否则返回所有顶点?”也许您可以添加更多详细信息和数据创建脚本我更新了我的问题,现在您有了更真实的查询,以便可以帮助我
g.V()
.hasLabel('user')
.project("userGroups")
.by(
as("appUser")
.both("friend")
.project("group")
.by(
union(
both('friend').where(neq('appUser')).where(both('friend').where(eq('appUser'))),
identity(),
select("appUser")
).order().by("name").values("name").fold()
).select(values).fold()
).select(values)
.repeat(unfold()).times(3)
// Here the groups of 2 members are removed:
.where(count(local).is(gt(2)))
.dedup()