Nebula 实现一些常用规则匹配语句写不出来

提问参考模版:

  • nebula 版本:(为节省回复者核对版本信息的时间,首次发帖的版本信息记得以截图形式展示)
  • 部署方式:单机
  • 安装方式: RPM
  • 是否为线上版本:N
  • 硬件信息
    • 磁盘( 推荐使用 SSD)
    • CPU、内存信息
  • 问题的具体描述
    我单机环境上部署Nebula,自己造了一点最简单的数据,是基于担保关系的,人这个点上有2个属性: 姓名,年龄,边只有类型是担保,无属性
    创建scheme:
CREATE SPACE `gr` (partition_num = 10, replica_factor = 1, vid_type = FIXED_STRING(64)) 
use gr;
CREATE TAG person(name string, age int);
CREATE EDGE grantee();
:sleep 20
insert vertex person(name,age) values "1":("小张", 42);
insert vertex person(name,age) values "2":("小李", 36);
insert vertex person(name,age) values "3":("老王", 65);
insert vertex person(name,age) values "4":("老邓", 42);
insert vertex person(name,age) values "5":("老蒋", 55);
insert vertex person(name,age) values "6":("小黑", 30);
insert vertex person(name,age) values "7":("老段", 55);
insert vertex person(name,age) values "8":("老钱", 61);
insert vertex person(name,age) values "9":("老孙", 68);
insert vertex person(name,age) values "10":("小吴", 21);

INSERT EDGE grantee () VALUES "1"->"2":();

INSERT EDGE grantee () VALUES "3"->"4":();
INSERT EDGE grantee () VALUES "4"->"3":();

INSERT EDGE grantee () VALUES "5"->"6":();
INSERT EDGE grantee () VALUES "6"->"7":();
INSERT EDGE grantee () VALUES "7"->"6":();
INSERT EDGE grantee () VALUES "6"->"5":();

  1. 想找到两两担保的,就是两个客户点,一个担保边,期望结果是 1–2(1给2做担保) ,3–4(3给4做担保) 这样的ngql 如何实现?

  2. 想找出两两互保,结果期望为3–4,4–3(3给4担保,4给3担保),这样的ngql 如何实现?

  3. 想找出整个担保链的,就是每个点以担保边往外扩散,一直扩散到结束,这样的语句如何实现?

  4. 找出循环担保链,也就是一个环,上面期望数据就是5–>6 6–>7, 7–> 6, 6–> 5 这样一个环,这样的Ngql 如何实现?

  5. 想找出一个点对应多有的入度或者出度点边,比如一个人给多个人担保,或者多个人给一个担保这样的一对多或多对一如何实现?

  6. 想找出图中金字塔形状的关系点边或者子图出来,比如一个担保人对应多个被担保人,多个被担保人本身也是担保人,又给其他人担保,就像一个金字塔状,这样使用Ngql 如何实现?

以上的6个问题,是目前将公司图库在切换到Nebula 之后,遇到的一些场景问题,切过来之后,因为对于Ngql 不是很熟悉,像上面的语句无法实现,也有些思考,但是就是不知道用ngql 如何表达:

  1. 简单担保: 条件1:边类型是担保, 条件2: 起始点出度=1 终止点出度=0
  2. 两两担保:匹配每个点出度为1,出度为1并且第一个点的出度==第二个点的入度
  3. 简单担保链: 按照边传递迭代下去,找到符合的点边 eg:
    match (a)-[*3]->(b) return a,b
  4. 循环担保: 简单担保链的特殊情况,起始点和终止点一样,也就是一个环,也就是如何实现环的检测
  5. 匹配每个点的入度,出度 > 1的点出来,没看到ngql如何求入度,出度
  6. 这个匹配点出度>1,然后扩展一直往外找

另外,这里有个小小的建议,目前Nebula 文档中列出来的这些Ngql 相关的语法,上面的语句能说明一下这句语句是什么意思么?看上面的例子都是以basketballplayer 为案例,希望能看着这个例子知道它业务上做了什么事情,另外,看了很多Nebula demo 演示这块的视频,大部分都是在讲场景,在演示的时候,语句就是执行一下,也不知道这语句为啥就是那样了,这是我们目前产品在切换到Nebula 的一些日常痛点,也一直在看Ngql 语法,但就是不知道咋写,Ngql 使用上这块介绍的内容较少,主要在语法文档上,这块建议能出一些demo视频或者文档上说明更完善,我们也在不断学习和适应Nebula 语法,希望更快能熟悉起来,谢谢

主要的查询语句在这里 https://docs.nebula-graph.com.cn/3.2.0/2.quick-start/4.nebula-graph-crud/#_7 ,除了这几个之外,还有 FIND PATH 和 GET SUBGRAPH。

简单来说如下:

===================

基本 nGQL 查询

  • GO ,沿着给定的点进行一步或者多步拓展,返回最后一跳的起点,边,或者终点
  • LOOKUP,从属性的条件反查点或者边,相应地,需要创建对应的点或者边上对应属性的的索引才行
  • FETCH,直接取给定的点、边上的属性

路径子图 nGQL

  • FIND PATH,查找两点间的路径
  • GET SUBGRAPH,从一个点出发获得子图

Cypher DQL

  • MATCH, 按照模式去查询,如果模式的起点条件里不能得出给定的 VID,大多数情况下像 LOOKUP 一样需要索引

===================

你的问题回答:

  1. 想找到两两担保的,就是两个客户点,一个担保边,期望结果是 1–2(1给2做担保) ,3–4(3给4做担保) 这样的ngql 如何实现?

可以用 LOOKUP 查边,也可以用 MATCH。
前者必须要建立 grantee 之上的索引,后者如果使用 LIMIT sample 的话,不建索引也可以

LOOKUP on grantee YIELD EDGE AS e 或者 MATCH ()-[e:grantee]->() RETURN e

参考:

关于索引的介绍,可以参考:https://docs.nebula-graph.com.cn/3.2.0/3.ngql-guide/14.native-index-statements/https://www.siwei.io/nebula-index-explained/

# 创建边(无属性)索引
CREATE EDGE INDEX grantee_index on grantee();
REBUILD EDGE INDEX grantee_index;


(root@nebula) [gr]> LOOKUP on grantee YIELD EDGE AS e # 需要边索引
+---------------------------+
| e                         |
+---------------------------+
| [:grantee "6"->"5" @0 {}] |
| [:grantee "6"->"7" @0 {}] |
| [:grantee "7"->"6" @0 {}] |
| [:grantee "1"->"2" @0 {}] |
| [:grantee "3"->"4" @0 {}] |
| [:grantee "4"->"3" @0 {}] |
| [:grantee "5"->"6" @0 {}] |
+---------------------------+

(root@nebula) [gr]> MATCH ()-[e:grantee]->() RETURN e LIMIT 10 #注,带有 LIMIT 之后,可以不需要索引查询。
+---------------------------+
| e                         |
+---------------------------+
| [:grantee "6"->"5" @0 {}] |
| [:grantee "6"->"7" @0 {}] |
| [:grantee "1"->"2" @0 {}] |
| [:grantee "7"->"6" @0 {}] |
| [:grantee "3"->"4" @0 {}] |
| [:grantee "4"->"3" @0 {}] |
| [:grantee "5"->"6" @0 {}] |
+---------------------------+
Got 7 rows (time spent 5845/217483 us)

Fri, 22 Jul 2022 17:48:50 CST

  1. 想找出两两互保,结果期望为3–4,4–3(3给4担保,4给3担保),这样的ngql 如何实现?

如果想查出所有的 3–4,4–3 这样的模式,可以用 MATCH 去表达,这时候,就必须建立索引(点索引边索引都可以,有了它才能避免全扫描数据,直接扫索引数据作为查询的起点)了。

模式就如你写出来的一样:(v:person)-[:grantee]->(v1:person), (v:person)<-[:grantee]-(v1:person)
查询的例子:

(root@nebula) [gr]> MATCH (v:person)-[:grantee]->(v1:person), (v:person)<-[:grantee]-(v1:person) return v,v1
+--------------------------------------+--------------------------------------+
| v                                    | v1                                   |
+--------------------------------------+--------------------------------------+
| ("6" :person{age: 30, name: "小黑"}) | ("7" :person{age: 55, name: "老段"}) |
| ("5" :person{age: 55, name: "老蒋"}) | ("6" :person{age: 30, name: "小黑"}) |
| ("7" :person{age: 55, name: "老段"}) | ("6" :person{age: 30, name: "小黑"}) |
| ("3" :person{age: 65, name: "老王"}) | ("4" :person{age: 42, name: "老邓"}) |
| ("4" :person{age: 42, name: "老邓"}) | ("3" :person{age: 65, name: "老王"}) |
| ("6" :person{age: 30, name: "小黑"}) | ("5" :person{age: 55, name: "老蒋"}) |
+--------------------------------------+--------------------------------------+
Got 6 rows (time spent 4921/54571 us)

其实这个查询本质上不是一个典型的(包括第一个问题)图查询,而是一个全图扫描的分析查询。

注,图查询(graph query)是从 给定的 少数点作为起点,向外拓展)
这是一个图查询,查询 “老王” 是否涉及两两担保

(root@nebula) [gr]> MATCH (v:person)-[:grantee]->(v1:person), (v:person)<-[:grantee]-(v1:person) 
                                WHERE id(v) == "3" RETURN v, v1
+--------------------------------------+--------------------------------------+
| v                                    | v1                                   |
+--------------------------------------+--------------------------------------+
| ("3" :person{age: 65, name: "老王"})  | ("4" :person{age: 42, name: "老邓"}) |
+--------------------------------------+--------------------------------------+
Got 1 rows (time spent 2307/29398 us)

  1. 想找出整个担保链的,就是每个点以担保边往外扩散,一直扩散到结束,这样的语句如何实现?

可以用MATCH 的模式去表达, 链的话,可以用 p=()-[].... return p 的方式,中间的边里边是可以用模糊的跳数去表达的,参考 https://docs.nebula-graph.com.cn/3.2.0/3.ngql-guide/7.general-query-statements/2.match/ , 不过当你说 "每个点”的时候,虽然就已经是一个图分析查询不是一个“图查询了”哈。

而如果是给定的点(不是每一个)的话,如果追求整个“链”也可以用 GET SUBGRAPH。

update: Sorry才看到你已经在写这个模式了,记得把能写的信息都写进去,比如边的类型

可以改成:

match p=()-[:grantee*1..3]->() return p

  1. 找出循环担保链,也就是一个环,上面期望数据就是5–>6 6–>7, 7–> 6, 6–> 5 这样一个环,这样的Ngql 如何实现?

参考上边


  1. 想找出一个点对应多有的入度或者出度点边,比如一个人给多个人担保,或者多个人给一个担保这样的一对多或多对一如何实现?

用 MATCH 的模式,结合 count 去表达条件是可以的。


  1. 想找出图中金字塔形状的关系点边或者子图出来,比如一个担保人对应多个被担保人,多个被担保人本身也是担保人,又给其他人担保,就像一个金字塔状,这样使用Ngql 如何实现?

如果不是从给定的点出发,这实际上这是一个图分析的查询,并不是一个图数据库的线上查询哈,比如“三角形计数”,比较适合用 GraphX,NetworkX 这类东西把图读到内存中去迭代运算得出。

不过这个模式再量小的时候,用 MATCH 也是可以表达的,参考上边哈。

3 个赞

另外后边我们会做一些教程帮助大家更容易知道到底有什么样的语句,什么类型的表达要怎么去写。

感谢花时间提这么中肯的意见哈~~

关于两个人在一个担保圈里的场景,也可以考虑用找路径的方式,即A->B有路径+B->A有路径,则可以说明A和B在一个担保圈里

1 个赞

嗯嗯,不过感觉他的需求都是图分析的查询,没有给定起点,全都是全图找特定规则的。

嗯,全图找是对历史数据做分析。
不过要真正发挥价值,还是建议在申请的实时链路上进行判断。这样可以有效阻止担保圈的形成。否则担保申请已经生效也很难撤销了,风险也形成了。

1 个赞

目前也想知道Nebula 如果做历史数据做分析,而不是特定的点向外扩展查询,目前是否能做?
这块理解下来就是批处理类似的需求了

对的,像这种规则匹配需求的,就是需要查整张大图去匹配出符合条件的结果,这个我们理解为符合条件的子图,看下来,使用subgraph 挺难实现

嗯嗯,不过这实际上是一个扫全图的图分析查询,不是一个典型的图数据库查询哈。

这种方式上使用图查询去做合理么,还是需要使用graphx 这种图计算框架?

目前看下来,我们的需求规则其实都是针对于所有的点,也就是图分析查询,不是OLAP即席查询,这时候使用Graphx 就有个问题,使用Graphx 是读取的是入图的原始文件呢?还是Nebula中的图数据,看了下Nebula-Algrithm源码,如果Grpahx 读取的是图数据的话,那构建图的时候,其实点边属性是没有的,我看只有权重,其他什么属性也没带过来,这块不清楚行业内做全图分析查询是直接基于NGQL还是 graphx 去读原始文件还是图库中数据,Graphx 和Nebula整合为啥没有把属性带过来呢?我理解的是是根据权重去做算法分析,纯数学计算,所以就不带这些点边属性了,但如果做Graphx 的话,其实是需要的

1 个赞

其实还是看咱们数据的量和数据里的具体情况,如果图库语句可以满足的话也是可以的,如果满足不了的话就只能上 graphx 这一类的计算框架了。

在 spark 里扫 nebula 数据的时候是可以选择读取属性的,不过肯定没有用图库写的查询语句那么方便。

我看大多数都是寻找一个 graph pattern,
这个用match应该可以写,不过查询数据量大的话,可能内存不够。
go 的路径是walk,可能会带入大量无效重复的边,不太推荐。
另外如果用spark的话,曾经有个很老的项目 https://github.com/opencypher/morpheus
剩下就是自己写scala在spark graphx上面运行了。

1 个赞

是用neo4j切换过来吗? 原来的是用cypher写的,还是apoc ?

之前的场景是基于Janus的,采用Gremlin 写的,现在产品想深度融合Nebula,在推进

那贴一下gremlin语句好了。
cypher和gremlin还是有很大的不同的,可以去学一下cypher

对的,其实就是想通过在产品上设定各种图规则,然后通过查询图也好,或者使用spark graphx 读取Nebula 数据然后使用图计算也好,去挖掘出符合规则的数据出来,其实就是想做图规则匹配,这块感觉直接使用ngql语句数据量大的话可能不大行,因为这个是对一张全图进行历史分析,数据量会比较大,可能更适合将全图读取出来,自己去实现每个规则的Pregel函数,根据图遍历完的结果可能再做进一步计算,不知道吴老师觉得这种图规则匹配这种处理是否合理,当然这块资源也肯定消耗巨大

1 个赞

图大的话,这样更可行吧,离线的计算集群一般都比较大。nebula 里面跑cypher找pattern的方式,只要复杂一点,我估计内存不够。

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