You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Nebula Graph中中断特定节点处的查询链?

Nebula Graph 遍历终止问题解决方案

环境信息

  • Nebula版本:3.8.0
  • 操作系统:Linux

问题描述

使用Nebula Graph数据库,需要编写查询语句,从节点a开始遍历关联链,当遇到特定节点c时终止该分支的遍历,忽略该节点之后的所有关联关系。

图结构如下:

j  -> k -> l
          |
a -> b -> c -> d -> e
     |
     f -> g -> h

期望得到的结果为:

a -> b
     |
     f -> g -> h

已创建顶点和边的语句如下:

USE ethereum;

-- Create addresses
INSERT VERTEX IF NOT EXISTS address() VALUES 'a':();
INSERT VERTEX IF NOT EXISTS address() VALUES 'b':();
INSERT VERTEX IF NOT EXISTS address() VALUES 'c':();
INSERT VERTEX IF NOT EXISTS address() VALUES 'd':();
INSERT VERTEX IF NOT EXISTS address() VALUES 'e':();
INSERT VERTEX IF NOT EXISTS address() VALUES 'f':();
INSERT VERTEX IF NOT EXISTS address() VALUES 'g':();
INSERT VERTEX IF NOT EXISTS address() VALUES 'h':();
INSERT VERTEX IF NOT EXISTS address() VALUES 'j':();
INSERT VERTEX IF NOT EXISTS address() VALUES 'k':();
INSERT VERTEX IF NOT EXISTS address() VALUES 'l':();

-- Establish relationships
INSERT EDGE erc20_transfer_to (transfer_timestamp, block_no, tx_hash, symbol) VALUES
"a" -> "b":(1622548800, 1234567, "0x123abc", "ETH");

INSERT EDGE erc20_transfer_to (transfer_timestamp, block_no, tx_hash, symbol) VALUES
"b" -> "c":(1622549800, 1234568, "0x456def", "ETH");

INSERT EDGE erc20_transfer_to (transfer_timestamp, block_no, tx_hash, symbol) VALUES
"c" -> "d":(1622550800, 1234569, "0x789ghi", "ETH");

INSERT EDGE erc20_transfer_to (transfer_timestamp, block_no, tx_hash, symbol) VALUES
"d" -> "e":(1622551800, 1234570, "0xabcjkl", "ETH");

INSERT EDGE erc20_transfer_to (transfer_timestamp, block_no, tx_hash, symbol) VALUES
"b" -> "f":(1622549800, 1234568, "0x456def", "ETH");

INSERT EDGE erc20_transfer_to (transfer_timestamp, block_no, tx_hash, symbol) VALUES
"f" -> "g":(1622550800, 1234569, "0x789ghi", "ETH");

INSERT EDGE erc20_transfer_to (transfer_timestamp, block_no, tx_hash, symbol) VALUES
"g" -> "h":(1622551800, 1234570, "0xabcjkl", "ETH");

INSERT EDGE erc20_transfer_to (transfer_timestamp, block_no, tx_hash, symbol) VALUES
"j" -> "k":(1622552800, 1234571, "0xdefmno", "ETH");

INSERT EDGE erc20_transfer_to (transfer_timestamp, block_no, tx_hash, symbol) VALUES
"k" -> "l":(1622553800, 1234572, "0xghipqr", "ETH");

INSERT EDGE erc20_transfer_to (transfer_timestamp, block_no, tx_hash, symbol) VALUES
"d" -> "j":(1622554800, 1234573, "0xklmstu", "ETH");

尝试的查询语句及返回结果:

GO 1 TO 5 STEPS FROM "a" 
OVER erc20_transfer_to
WHERE dst(edge) != "c"
YIELD src(edge) AS src, dst(edge) AS dst, edge AS e

返回结果仍包含c->d、d->e等不符合期望的边:

src | dst | e
---|---|---
a | b | [:erc20_transfer_to "a"->"b" @0 {block_no: 1234567, symbol: "ETH", transfer_timestamp: 1622548800, tx_hash: "0x123abc"}]
-- | -- | --
j | k | [:erc20_transfer_to "j"->"k" @0 {block_no: 1234571, symbol: "ETH", transfer_timestamp: 1622552800, tx_hash: "0xdefmno"}]
b | f | [:erc20_transfer_to "b"->"f" @0 {block_no: 1234568, symbol: "ETH", transfer_timestamp: 1622549800, tx_hash: "0x456def"}]
f | g | [:erc20_transfer_to "f"->"g" @0 {block_no: 1234569, symbol: "ETH", transfer_timestamp: 1622550800, tx_hash: "0x789ghi"}]
c | d | [:erc20_transfer_to "c"->"d" @0 {block_no: 1234569, symbol: "ETH", transfer_timestamp: 1622550800, tx_hash: "0x789ghi"}]
d | e | [:erc20_transfer_to "d"->"e" @0 {block_no: 1234570, symbol: "ETH", transfer_timestamp: 1622551800, tx_hash: "0xabcjkl"}]
d | j | [:erc20_transfer_to "d"->"j" @0 {block_no: 1234573, symbol: "ETH", transfer_timestamp: 1622554800, tx_hash: "0xklmstu"}]
g | h | [:erc20_transfer_to "g"->"h" @0 {block_no: 1234570, symbol: "ETH", transfer_timestamp: 1622551800, tx_hash: "0xabcjkl"}]

问题分析

原查询仅过滤了目标节点为c的边,但无法阻止遍历过程中已经到达c后继续向下遍历的分支,也无法排除从c出发的后续边。需要通过跟踪遍历路径,确保不会进入包含c的分支,同时终止该分支的递归遍历。

解决方案

使用Nebula的**递归查询(RECURSIVE WITH)**来跟踪遍历路径,在每一步判断是否遇到c,若遇到则停止该分支的继续遍历:

RECURSIVE WITH
  -- 初始遍历:从a出发,排除目标为c的边,记录初始路径
  GO FROM "a" OVER erc20_transfer_to
  YIELD src(edge) AS src, dst(edge) AS dst, edge AS e, [src(edge), dst(edge)] AS path
  WHERE dst != "c"
UNION ALL
  -- 递归遍历:从上一步的目标节点继续,确保路径中无c,且目标节点不是c
  GO FROM $-.dst OVER erc20_transfer_to
  YIELD src(edge) AS src, dst(edge) AS dst, edge AS e, $-.path + [dst(edge)] AS path
  WHERE dst != "c" AND NOT "c" IN $-.path
-- 最终返回需要的字段
YIELD src, dst, e

结果验证

执行上述查询后,返回结果将仅包含符合期望的边:

src | dst | e
---|---|---
a | b | [:erc20_transfer_to "a"->"b" @0 {block_no: 1234567, symbol: "ETH", transfer_timestamp: 1622548800, tx_hash: "0x123abc"}]
b | f | [:erc20_transfer_to "b"->"f" @0 {block_no: 1234568, symbol: "ETH", transfer_timestamp: 1622549800, tx_hash: "0x456def"}]
f | g | [:erc20_transfer_to "f"->"g" @0 {block_no: 1234569, symbol: "ETH", transfer_timestamp: 1622550800, tx_hash: "0x789ghi"}]
g | h | [:erc20_transfer_to "g"->"h" @0 {block_no: 1234570, symbol: "ETH", transfer_timestamp: 1622551800, tx_hash: "0xabcjkl"}]

成功在遇到c时终止对应分支的遍历,完全符合需求。

内容的提问来源于stack exchange,提问作者Moon soon

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.19 23:20:56