go和match的区别

  • nebula 版本:2.0.1
  • 部署方式(分布式 / 单机 / Docker / DBaaS):分布式
  • 是否为线上版本:Y / N
  • 硬件信息
    • 磁盘( 推荐使用 SSD) ssd
    • CPU、内存信息 96c
  • 问题的具体描述

1.opencypher 的实现方式与原始的ngql语句有什么不一样?
在实际测试中的例子,go要比match快很多。。

match方式

profile MATCH (v:card) -[e:transfer]-> (v2:card) -[f:transfer]-> (v3:card) where id(v) == '11100000' and e.transtime>=1604156400000 and e.transtime<=1609426800000 and f.transtime>=1604156400000 and f.transtime<=1609426800000 RETURN id(v), sum(f.amount);


go方式

profile go from '10000000' over transfer REVERSELY where transfer.transtime>=1606752000000 and transfer.transtime<=1609430399000 
YIELD transfer._dst AS card |
  GO FROM $-.card over transfer REVERSELY where transfer.transtime>=1604160000000 and transfer.transtime<=1609430399000 YIELD transfer.amount as amount | return sum($-.amount)

从执行计划上可以很清楚看到go的方式比match快了一倍

2.go语句怎么实现聚合判断过滤再进行下一次扩散
match写法

profile match l=(v:email)-[:email_idcard]->(ids1:idcard)<-[:phone_idcard]-(phone:phone)-[:phone_idcard]->(ids2:idcard) where id(v)=="email|2_test@zju.edu.cn" 
with v, count(distinct phone) as pnum,count(distinct ids1) as ids1,count(distinct ids2) as ids2 
where pnum > 0 and ids1>5 and ids1 < 200 and ids2 > 5 and ids2 < 300  
return v.email_id,  pnum,ids1,ids2,  true as result
 

执行计划如下

这个语句较为复杂,四度关联加聚合判断。
鉴于上边的问题,想把这个语句改为go的方式,发现count之后可以判断,但是无法得到下一次扩散的起始点了,如果再次扩散就无法得到聚合结果进行判断。不知道该怎么实现。
比如
go from "xxx" over email_idcard yield email_idcard._dst as id1 | go from $-.id1 over phone_idcard
这样可以扩散,但是判断加不进去
go from "xxx" over email_idcard yield size(collect(email_idcard._dst as id1) )
这样可以聚合但是无法下一步使用id1扩散了
官方例子较为简单,是否有更复杂的一些示例呢。

3.目前还是存在一些操作会引起graphd崩溃

YIELD case COUNT($-.var_idcards) ==100  when true THEN 1 ELSE 0 END as aa

case 后边跟聚合函数,graphd直接挂掉,我在之前发的帖子里边也有提到别的情况。
在生产环境由于一个查询就挂掉这太不安全了。。。

以上

1 个赞
  1. match扩展的是路径,go只是终点的扩展,所以match在扩展的同时会join当前的起点和之前的终点,这样一整条独立的路径产生一个结果,而go则是一个独立的扩展产生一个结果
  2. match会去除环路结果
1 个赞

判断用where,扩展yield id就可以

crash的问题麻烦去提个issue


但是 where 后边是不能跟聚合函数的
我想要聚合一度的个数,判断是否大于n,满足条件再继续往下扩散
试了很多写法都没实现…

yield应该是支持聚合的,你可以yield到下一句判断


提示go 不支持聚合函数

这样可以聚合,但是又拿不到id1进行扩散了

是指这样的么?

(root@nebula) [nba]>  go 2 step from 'Tony Parker' over like yield like._dst as id1 | yield $-.id1 as id2, count($-.id1) as count
+-----------------+-------+
| id2             | count |
+-----------------+-------+
| "Manu Ginobili" | 1     |
+-----------------+-------+
| "Tim Duncan"    | 2     |
+-----------------+-------+
| "Tony Parker"   | 2     |
+-----------------+-------+
Got 3 rows (time spent 2165/8238 us)

Mon, 21 Jun 2021 20:56:13 CST

(root@nebula) [nba]>
(root@nebula) [nba]>
(root@nebula) [nba]>
(root@nebula) [nba]>
(root@nebula) [nba]>
(root@nebula) [nba]>
(root@nebula) [nba]>  go 2 step from 'Tony Parker' over like yield like._dst as id1 | yield $-.id1 as id2, count($-.id1) as count | yield $-.id2, $-.count  where $-.count == 2
+---------------+----------+
| $-.id2        | $-.count |
+---------------+----------+
| "Tony Parker" | 2        |
+---------------+----------+
| "Tim Duncan"  | 2        |
+---------------+----------+
Got 2 rows (time spent 2025/9141 us)

Mon, 21 Jun 2021 20:56:15 CST

我按照这个尝试了一下,发现逻辑还是不一样的,你这是以第一层扩散的节点为key 按照第二层扩散的节点做分区求count,跟我的逻辑不太一样。
我的逻辑是,以起始点为key,计算第一层扩散的节点的count,满足条件从第一层节点继续扩散,拿到第二层的节点,然后仍然按照起始点为key求第二层节点的count。
go是没有将结果join的,所以扩散到第二层的时候,起始节点和第二层节点不在同一维度上,所以没法求count,看来go是不能实现我这个场景,只能使用match了。。

  1. go 语句设计是用来做简单扩散的,match 是基于全路径的,所以实现上相应的 match 开销也会比 go 大,而且执行计划上 match 还有很多优化空间

  2. cypher 的 pattern 描述能力比原生 nGql 要强很多,类似这样复杂的语句 nGql 确实很难实现。cypher 的 pattern 不仅能方便地描述拓扑并将具有特定特征(拓扑或属性特征)的数据收集到 label 变量中,而且具备描述复杂扩散模式的能力,nGql 的管道作用范围也仅仅在管道前后,用自定义变量的话也很难处理复杂拓扑和属性过滤同时存在的场景。而且最大的区别是两种语言的扩散方式定义不同,cypher 中的路径是允许点重复不允许边重复的,而 go 语句是允许点边重复的,一些能用 cypher 描述的语句场景并不总能用 go 语句描述,反之也是同理。

  3. Fixed https://github.com/vesoft-inc/nebula-graph/pull/1186

3 个赞

是的,并不能简单地切割 pattern,pattern 是一个整体

该主题在最后一个回复创建后7天后自动关闭。不再允许新的回复。