路径查找中过滤

提问参考模版:

  • nebula 版本:v3.4.1
  • 部署方式:分布式
  • 安装方式: RPM
  • 是否上生产环境:Y
  • 硬件信息
    • 磁盘( 推荐使用 SSD)
    • CPU、内存信息
  • 问题的具体描述
    需求: 找出对外投资路径中企业是非注销状态,最多展示20层
    需求: 找出对外投资路径中存在公司不为 "注销"状态的路径,最多展示20层。

所以为了实现这个需求,存在的问题是:

subgraph 只是目的点过滤,这个就不太符合需求了。因为路径的中间点有可能是满足的
是要返回全部路径的
那这个和subgraph 一样,应该也是不太符合需求了
这个需求该怎么用语句表达呢?

目前有两种想法:

  1. 用Get Subgraph
GET SUBGRAPH WITH PROP 20 STEPS FROM 815677140545765099 OUT Invest YIELD VERTICES as nodes, Edges as rels

但是这个问题是语句中如何过滤 Company.shortstatus != "注销"的路径呢?

  1. 用Match 或者Go 总觉得表达上有缺失, 同时也担心有性能问题
match p=(v:Company)-[r:Invest*1..20]->(dst) where id(v)==815677140545765099 and dst.Company.shortstatus!="注销" return p


go 1 To 20 STEPS FROM 815677140545765099  OVER Invest  where properties($$).shortstatus!="注销" yield DISTINCT dst(edge) as id
这个go 语句的想法是先拿到终点,再并发用FIND PATH 找路径

现在的问题是:

  1. subgraph 可以在语句中过滤吗? 业务上过滤20层数据感觉会很多
  2. match 和 go 的表达虽然是用了不定长路径,但都是终点满足条件,不确定这个语义上是否符合需求
  3. 我初始以为 第二个方法里面match 和go 的语义应该是相同的,但是测试后发现结果不一致
  1. subgraph支持过滤目的点
    GET SUBGRAPH - NebulaGraph Database 手册

  2. 如果你只要返回目的点的话,不需要p这个变量

  3. 2是返回的路径,3返回的是目的点。同时,go的多跳的过滤是对最后一跳做过滤,中间没有做过滤

不好意思,需求表达不够准确,
需求: 找出对外投资路径中企业是非注销状态,最多展示20层
找出对外投资路径中存在公司为 "在业"状态的路径,最多展示20层。

所以为了实现这个需求,存在的问题是:

  1. subgraph 只是目的点过滤,这个就不太符合需求了。因为路径的中间点有可能是满足的
  2. 是要返回全部路径的
  3. 那这个和subgraph 一样,应该也是不太符合需求了

这个需求该怎么用语句表达呢?

ping…

GET SUBGRAPH 支持对图中经过的点的属性做过滤的,可以直接在 WHERE 中加过滤:

GET SUBGRAPH WITH PROP 20 STEPS 
FROM 815677140545765099 OUT Invest 
WHERE $$.Company.shortstatus != "注销"
YIELD VERTICES as nodes, Edges as rels

这个只是最终的叶子节点吧? 中间路径上的满足条件的也希望保留的

是对每一步都进行过滤的,可以通过执行计划上看出来:

哦哦,想了想也不太满足。
现在这个是ALL(path node), 其实我需要的是Any(path node) 存在一个满足条件即可。

也想过把把属性放到边上,也有这个问题

我感觉两个好像是等价的 :joy:

任意一条路径上经过此类顶点就排除该路径,不就相当于先把此类顶点都排除之后找路径。暂时没想到什么路径不经过该类型的顶点,同时又不在后者的子图上。感觉满足条件的路径肯定和后者的子图是联通的,所以拿子图肯定能将该路径囊括进来。

你看这么两个路径:

  1. A -[Invest] ->B -[Invest]->C-[Invest]->D
  2. A -[Invest] ->F -[Invest]->G-[Invest]->H

B shortstatus 是在业,C在注销
F,G,H shortstatus 是注销
如果用shortstatus != 注销 是不是 1 也会被过滤掉。 但是1其实是满足条件的。

是说路径上允许一个顶点满足注销的条件?不是说路径上只要有一个点满足注销的条件,该路径就过滤?

如果是上述1的表达,那确实不能把所有的都过滤。这只能是在找路径的过程中检查当前路径是否满足条件了

路径上只要有一个点满足注销的条件,该路径就该保留。
目前是这样的需求。怎么可以实现这样的查询需求吗?

哦哦,我理解错了。

有试过先找所有的路径然后再过滤掉全是注销的路径的做法吗?

  • Get subgraph 之后业务层过滤吗?想尽量在查询层得到这个结果。下下策是这么实现
  • 还有点担心Get subgraph 20 层数据量太多,性能不太好,想看看有没有其他实现方式做下对比

get subgraph 只能返回点边的集合,不知道现在如何处理的路径?有一种做法就是通过 subgraph 拿到所有的 20 跳的终点,然后 pipe 给 find all path 来找路径,再进行过滤。

或者通过图计算的方式找路径,这种偏向深度的查询可以用图计算的方式并行的迭代计算。

  1. 我可能没表达清楚需求。从某个点往外扩展20层,路径满足存在某个点不为注销就保留该路径。这样 get subgraph 返回的子图,有点边的关系,拼成路径就可以了。不需要pipe 给FIND ALL PATH, 20层SubGraph 本来性能就不是很好,传一次会更糟糕吧。
  2. 目前是OLTP 的需求,图计算的方式实时性和响应都难以满足需求。

昨天做了压测,用get subgraph 获取20层,然后业务上遍历做过滤。性能较差,平均2s了。

有些超时(>10s)的看了下返回的数据量大小,过滤前,sum(size($-.v))=114023, sum(size($-.e))=135395, 这个也没想象的那么多。

请问目前这个有什么较好的查询语句写法吗?

性能差的原因是 get subgraph 这块时间就超过限制了,还是加上了业务层拼接的代码?

因为现在的过滤需要走完 20 步才能终止,无法提前结束,所以现有的过滤方法都失效了。

另外的一个想法是,用 go 走 20 步,获取到所有的终点,然后用 find all path 找起点到这些终点的所有的路径。find all path 的并发实现比 subgraph 好点,不知道这样都在服务端执行会不会比之前的服务端+客户端的总时间更好些,这个具体还要你们来验证。

不过总体而言,你们的这个场景还是对我们的启发还是很大的,我们会在新版本中将相关的实现迭代到新的框架中。非常感谢!

cc @MuYi

1 个赞

只是get subgraph, 业务层的拼接耗时目前没有算进来。
我之前有想过是不是数据量太大,传输耗时也比较久。但是看起来超时的数据量没有太大(10w) 左右。

第二个想法,有想过,但是具体实现上,这个过滤怎么写呢? 我现在的问题在于这个过滤条件是对所有层级上做Any,不是ALL,这个导致我不知道具体怎么写:sweat_smile:

想先问下,现在match 20跳,不做任何过滤的话,效率大概多高?能否满足时间需求?如果可以满足的话可以考虑用reduce来做过滤

match p=(v:Company)-[r:Invest*1…20]->(dst) where id(v)==815677140545765099 return p
这个的效率