NebluaGraph 是否能解决我们业务出现的问题?

我们现在业务上有一个需求,普通的关系型数据库没有好的解决方案,所以想考虑使用一下图数据。
刚好了解到我们这款产品,看看能否能解决我们目前的业务问题? 如果可以的话,我们就准备开始试用一下。

我们的需求是这样的:
我们现在有大量的用户,用户之间只是简单的上下层级关系,但是关系层次比较深(1000层以上),可以简单理解成为一个深度较大的二叉树。 节点上的用户每天都会产生大量订单。

现在我们需要对数据进行聚合统计。

比如 从某个节点开始,遍历到它所有的下级。 统计一段时间以内所有节点产生的订单聚合信息(总额,数量或者其他)。

这是我们一个比较简单的需求。 我现在对NebluaGraph 的了解是,你们的产品可以支持大量的节点和关系的查询。
但是是否能支持,每个节点产生的大量订单信息的存储?以及快速的订单的数据统计聚合查询?

1 个赞

如果是单点出发的多跳查询,都算是比较 graphy(偏图的)
图数据库(NebulaGraph)的优势是少数点出发的高并发读写场景多跳探索。
图数据库不擅长的查询其实就是典型的 SQL/Tabular 数据库的类似于 SELECT 的查询,或者类似于 Elastic 的倒排索引的查询,或者需要全图迭代的情形(图计算平台)。

把少数点出发向外跳转返回结果的查询(如果数据主库上 hold 不住)放到图库上是最典型的选型场景。

NebulaGraph 擅长处理总量千亿点、万亿边的数据,这也是为什么很多大厂选择 NebulaGraph,好处就是不用担心未来业务增长一两个量级,图库这层需要换方案。

不过实际的情况下,平均起来点之间的连接程度(比如平均点的度)对于具体查询的表现可以差很多,如果不加以条件过滤、剪枝,稍微连接紧密一点的图上,很少几跳就可以覆盖全图数据了。

从你的上下级的需求看,我不认为一个查询会覆盖全图,初步推测是没有问题的,当然,做 PoC 去验证是最能回答你的问题的。

你可以从数据建模、导入、到业务 query 的撰写开始,在 NebulaGraph 社区一点点讨论着搞起来试试哈,NebulaGraph 社区非常欢迎和你一起研究怎么满足你的需求,或者甚至最后发现不适合(比如实际上是非图的 query pattern、需要图计算平台的 AP 场景),也许还能给出其他方案的建议。

1 个赞

好的,非常感谢您的回复,后续我会实际搭建数据库去试一下。

另外我重新回顾了一下我的问题,可能有些地方描述的不是特别好。

我重新描述一下问题,一共有两个问题。

我们的实际需求是,从二叉树的顶点出发,查找 顶点到二叉树下面所有子节点(深度 1000+)路径节点产生的订单总数,以及金额统计? 图数据库是否能有效支持?

第二个问题
我昨天是第二天学习我们这个图数据的,描述一下我大概的建模思路。

定义 tag 用户
定义 tag 订单
定义 tag 商品
定义 edge 上下级关系 关联用户 tag
定义 edge 用户订单关系 关联用户 tag
定义 edge 商品订单关系 关联订单 tag

每生成一个用户,新增用户到 上下级关系网。
用户每生成一个订单,就新增订单到 用户订单关系上。 商品关联到订单tag节点上。

这种建模方式,是否能适用于我上述的这个查询需求?

取子树那里GO应该会比较快,用where来做个剪枝
先把所有叶子的id取回来,看看要不要去重
然后再根据叶子id把你的属性FETCH取回来,这里再sum下

可以试试,挺好玩的场景。

好奇问下为什么会有那么深?是上下游推荐这样的金字塔嘛?

如果是单纯的上下级DAG还好,如果你下级有个回环到某个上级,这里路径去重的计算量就很大了。

1 个赞

嗯,对的。业务是直销的业务模式,用户上线级关系是典型的金字塔关系,且关系没有回环。关系也特别简单。
我们需求是按照上级查询所有下级订单业绩的需求。性能要求就是速度快。这个关系型数据库很难做。

按照您这边的说法,我可以去尝试了。非常感谢

你好,我按照您这边的说法,试了一下,但是查询效率很差,可能是我哪里的写法有问题

第一行 我取的是 节点 B11511111 这个用户子树下的所有ID。 大概数量有56800个。
第二行 取的是这些ID 的用户 在今年第一周(订单时间加了索引)下的订单的所有金额。
第三行 求和。

查询时间大概3S 左右。 我的数据库服务器是8C16G的配置。

请问有什么办法可以优化吗?

试试把properties($$).prop 换成 $$.tag.prop的形式

非常感谢。确实 起作用了,查询原来时间是3秒,修改以后变成了1.9秒。

但是与我预想的差距还有点远。我希望毫秒级的处理完成,还有改进空间吗?

  1. dst(edge)改写成 id($$)
  2. 还可以试试yield id($$) as id 那里加个distinct, 写成 yield distinct id($$) as id. 是否变快和你的数据有关, 你可以测下.
1 个赞

然后下次打个profile,我们看下耗时

storaged有个配置参数,你可以手动加上试试。

1 个赞

这个是执行计划显示的内容

不好意思,3.3.0版本的文档,没有找到 query_concurrently 这个配置

感谢,这个条件加了以后 又快了0.1秒 :sweat_smile: 变成1.8s了

手动加,我记得3.3代码已经有了

好的 我试试

我看profile的大头是 GetDstBySrc 每次要2ms,然后要跑1000次?

嗯,查询语句有点问题,我重新写了一下。

按照你这边的要求,我加上了 多线程查询的参数 query_concurrently=true。效率确实提升了1倍。

现在查询时间为1秒左右。

但是这个时间太长,还达不到预期的结果。

这个是优化过后的查询语句
第一行查节点下级的用户ID
第二行查节点用户下过的订单
第三行是统计总额

go 0 TO 10000 steps from "B11511111" over develop yield id($$) as id |
go  from $-.id over buy  where  $$.czt_order.payment_on <  datetime('2023-01-07')  and  $$.czt_order.payment_on  >  datetime('2023-01-01')  yield  $$.czt_order.total as price | 
yield sum($-.price)

这个是profile
result (1).csv (153.7 KB)

存储计算分离好像不适合这种非常深度的场景
你试试memgraph这种内存型的呢?