FIND PATH 查询最短路径时,对中间节点进行聚合操作

我的数据中的数据结构如下:

tags:
  person(phone, xm, ...) 
edges:
  record(start_time, ...)

其中:

  • personid 取的是 phone
  • recordsrc,dst 也是 phone, rank 取的是 start_time 的时间戳;
  • 两个点之间可能有几百上千条边;

我的需求:

  1. 我现在使用 find shortest path 语句查询两点之间的最短路径,但是因为两个点之间有很多条边,返回的结果很多记录中间节点都是重复的;
  2. 我的需求是只关注中间节点,如果中间节点一样就取其中一条,或者调用聚合函数对边进行聚合操作;

我现在的 ngql 如下:
只是取了 path 路径的所有的,该如何聚合操作呢?

FIND SHORTEST PATH FROM <vid1> TO <vid2> OVER * BIDIRECT YIELD PATH AS p |
YIELD NODES($-.p) AS vnodes;

或者还有什么方法可以在数据库中全库搜索最短路径的方法?

问下,这种情况下,你期望结果是啥?

# 查找所有从 player100 到 team204 无环路径。
nebula> FIND NOLOOP PATH FROM "player100" TO "team204" OVER * YIELD path AS p;
+--------------------------------------------------------------------------------------------------------+
| p                                                                                                      |
+--------------------------------------------------------------------------------------------------------+
| <("player100")-[:serve@0 {}]->("team204")>                                                             |
| <("player100")-[:follow@0 {}]->("player125")-[:serve@0 {}]->("team204")>                               |
| <("player100")-[:follow@0 {}]->("player101")-[:serve@0 {}]->("team204")>                               |
| <("player100")-[:follow@0 {}]->("player101")-[:follow@0 {}]->("player125")-[:serve@0 {}]->("team204")> |
| <("player100")-[:follow@0 {}]->("player101")-[:follow@0 {}]->("player102")-[:serve@0 {}]->("team204")> |
| ...                                                                                                    |
+--------------------------------------------------------------------------------------------------------+

您说的这种情况中间点没有重复的,下面我加了两条路径

增加路径之后的结果

# 查找所有从 player100 到 team204 无环路径。
nebula> FIND NOLOOP PATH FROM "player100" TO "team204" OVER * YIELD path AS p;
+--------------------------------------------------------------------------------------------------------+
| p                                                                                                      |
+--------------------------------------------------------------------------------------------------------+
| <("player100")-[:serve@0 {}]->("team204")>                                                             |
| <("player100")-[:follow@0 {}]->("player125")-[:serve@0 {}]->("team204")>                               |
| <("player100")-[:follow@0 {}]->("player101")-[:serve@0 {}]->("team204")>                               |
| <("player100")-[:follow@0 {}]->("player101")-[:follow@0 {}]->("player125")-[:serve@0 {}]->("team204")> |
| <("player100")-[:follow@1 {}]->("player101")-[:follow@1 {}]->("player125")-[:serve@1 {}]->("team204")> |
| <("player100")-[:follow@0 {}]->("player101")-[:follow@0 {}]->("player102")-[:serve@0 {}]->("team204")> |
| <("player100")-[:follow@1 {}]->("player101")-[:follow@1 {}]->("player102")-[:serve@1 {}]->("team204")> |
| ...                                                                                                    |
+--------------------------------------------------------------------------------------------------------+

我需要的结果: 意思就是,将中间节点一样的路径看作是重复的路径,就保留其中一条

# 查找所有从 player100 到 team204 无环路径。
nebula> FIND NOLOOP PATH FROM "player100" TO "team204" OVER * YIELD path AS p;
+--------------------------------------------------------------------------------------------------------+
| p                                                                                                      |
+--------------------------------------------------------------------------------------------------------+
| <("player100")-[:serve@0 {}]->("team204")>                                                             |
| <("player100")-[:follow@0 {}]->("player125")-[:serve@0 {}]->("team204")>                               |
| <("player100")-[:follow@0 {}]->("player101")-[:serve@0 {}]->("team204")>                               |
| <("player100")-[:follow@0 {}]->("player101")-[:follow@0 {}]->("player125")-[:serve@0 {}]->("team204")> |
| <("player100")-[:follow@0 {}]->("player101")-[:follow@0 {}]->("player102")-[:serve@0 {}]->("team204")> |
| ...                                                                                                    |
+--------------------------------------------------------------------------------------------------------+
FIND all PATH FROM "player100" TO "team204" OVER * YIELD distinct path AS p;

你加个 distinct 试试

我刚刚试了一下,没有实现去重效果;

可不可以支持一下 :grinning:呢?检索双向最短路径的时候,可以设置是否只遍历两个点之间的一条边;不然的话如果两条边之间有100条边,最后返回的结果量级就要乘以100,而且如果都遍历的话还特别耗时,感谢。

你的结果方便贴上来瞅瞅吗?

这里的问题是,你想要的是路径还是边。如果是路径的话,一条边标识的是一条路径。
find all/noloop path的目标就是要找到所有路径。因为后续可能还有根据边上的权重做排序等操作;

另外,你只是要最短路径吗?最短路径用 shortest path 就可以了吧?

是的,我就是用的 find shortest path,返回的结果还有很多中间节点一样但是边的rank值不一样的(这些对我来说算是重复路径),我需要的是忽略rank,只要两个点之间有一个边被遍历过,就忽略这两个点之间的其他边了

这个很简单,最短路径是一跳,如果是两跳,最后的结果的量级就要相乘了

你可以用 match 里的 shortestpath

后面 3.7 发布以后,find path 里有 single shortest ptah 也是一样的。

好的感谢

我测试了一下 使用 match检索最短路径时有一个问题:

  • 就是他只会返回一条路径,如果这两个点之间还可以通过其他点连通,就无法把两条路径都返回

比如说:

假设 a 到 e,有一下两条最短路径,他就只会返回其中一条,无法全部返回 
a->b->c->d->e
a->f->c->d->e 

然说可以忽略 rank 值,但是会漏了中间节点不同的路径,所以会遗漏一些信息,这种需求能不能实现呢?感谢

此话题已在最后回复的 30 天后被自动关闭。不再允许新回复。