概述
路径模板n()...n()
将点模板和边模板按顺序串联,形成特定路径结构。使用路径模板可以从图中获取与描述的模式或结构匹配的路径。
点模板和边模板
点模板和边模板是路径模板的构建要素,共分为以下四种:
模板 |
名称 |
描述 | 别名类型 |
---|---|---|---|
n() |
单点模板 | 代表路径中的单个点:![]() |
NODE |
e() ,le() ,re() |
单边模板 (方向:双向、左向、右向) |
代表路径中的单条边:![]() |
EDGE |
e()[<steps>] ,le()[<steps>] ,re()[<steps>] |
多边模板 (方向:双向、左向、右向) |
代表路径中的多条连续边:![]() [<steps>] 格式(N≥0):
0 时,当且仅当边模板前的点与边模板后的点重合时有效。此时边模板被忽略,两侧的两个点将被视作单个点 |
N/A |
e().nf()[<steps>] ,le().nf()[<steps>] ,re().nf()[<steps>] |
有中介点的多边模板 (方向:双向、左向、右向) |
代表路径中多条连续的边及其之间的点: ![]() [<steps>] 格式与多边模板中相同 |
N/A |
过滤器包裹在{}
中,作用在括号内的所有点边模板上,更加精确地定义相应点边的schema和属性。此外,路径模板中的首个单点模板n()
允许直接引用别名。
构建路径模板
路径以点开始,以点结尾,其间点边交替出现。值得注意的是,路径也可以仅由单个点组成,不包含任何边。依照该规则,可以构建符合特定场景的路径模板。请参考以下示例。
查找由Kavi喜欢的用户推荐的书:

n({@user.name == "Kavi"}).re({@likes}).n({@user}).re({@recommends}).n({@books} as b)
return b.name
查找C34
持有的账户到C135
持有的账户间1到3步出向交易路径:

n({_id == "C34"}).re({@owns}).n({@account}).re({@transfers})[3].n({@account}).le({@owns}).n({_id == "C135"}) as p
return p{*}
查找C34
持有的账户到C135
持有的账户间的3步交易路径,其中中间账户的level
属性值大于4:

n({_id == "C34"}).re({@owns}).n({@account}).e({@transfers}).nf({@account.level > 4})[:3].n({@account}).le({@owns}).n({_id == "C135"}) as p
return p{*}
查找3到5步的任务依赖环形路径:

n({@task} as t).re({@dependsOn})[3:5].n({_id == t._id}) as p
return p{*}
本条查询重复使用了路径模板中的别名t
,从而形成环形结构。
语法
- 语句别名:类型为
PATH
- 方法可以在路径模板后串联使用:
方法 |
参数 |
描述 | 可选 |
别名类型 |
---|---|---|---|---|
no_circle() |
/ | 剔除含有环路的路径。路径有重复点时意味着有环路出现 | 是 | N/A |
limit() |
<N> |
限制每个起点返回的路径数(N ≥-1);-1 返回所有路径 |
是 | N/A |
示例图集1

在一个空图集中,逐行运行以下语句,创建示例图集:
create().node_schema("country").node_schema("movie").node_schema("director").edge_schema("filmedIn").edge_schema("direct").edge_schema("bornIn")
create().node_property(@*, "name").edge_property(@direct, "year", int32).edge_property(@bornIn, "year", int32)
insert().into(@country).nodes([{_id:"C1", name:"France"}, {_id:"C2", name:"USA"}, {_id:"C3", name:"Canada"}])
insert().into(@movie).nodes([{_id:"M1", name:"Léon"}, {_id:"M2", name:"The Terminator"}, {_id:"M3", name:"Avatar"}])
insert().into(@director).nodes([{_id:"D1", name:"Luc Besson"}, {_id:"D2", name:"James Cameron"}])
insert().into(@filmedIn).edges([{_from:"M1", _to:"C1"}, {_from:"M1", _to:"C2"}, {_from:"M2", _to:"C2"}, {_from:"M3", _to:"C2"}])
insert().into(@direct).edges([{_from: "D1", _to: "M1", year: 1994}, {_from: "D2", _to: "M2", year: 1984}, {_from: "D2", _to: "M3", year: 2009}])
insert().into(@bornIn).edges([{_from: "D1", _to: "C1", year: 1959}, {_from: "D2", _to: "C3", year: 1954}])
找点
可以在单点模板n()
中声明别名。
查找点@movie
:
n({@movie} as m)
return m.name
结果:
m.name |
---|
The Terminator |
Léon |
Avatar |
查找电影Léon
拍摄所在国家:
n({@movie.name == "Léon"}).e({@filmedIn}).n(as c)
return c.name
结果:
c.name |
---|
France |
USA |
找边
可以在单边模板e()
中声明别名。
查找电影The Terminator
的导演时间:
n({@movie.name == "The Terminator"}).e({@direct} as d).n()
return d.year
结果:
d.year |
---|
1984 |
查找固定长度路径
查找描述所有在USA
拍摄的电影及其导演的路径:
n({@country.name == "USA"}).le().n({@movie}).e().n({@director}) as p
return p{*}
结果:p

查找电影Léon
和The Terminator
之间的2步路径:
n({@movie.name == "Léon"}).e()[2].n({@movie.name == "The Terminator"}) as p
return p{*}
结果:p

查找可变长度路径
查找Luc Besson
和France
之间的4步内路径:
n({name == "Luc Besson"}).e()[:4].n({name == "France"}) as p
return p{*}
结果:p

查找Luc Besson
和France
之间的4步内路径,且不经过电影Léon
:
n({name == "Luc Besson"}).e().nf({name != "Léon"})[:4].n({name == "France"}) as p
return p{*}
结果:p

查找最短路径
查找Luc Besson
和France
之间4步内的最短路径:
n({name == "Luc Besson"}).e()[*:4].n({name == "France"}) as p
return p{*}
结果:p

剔除环路
查找Léon
和USA
之间的4步内路径:
n({name == "Léon"}).e()[:4].n({name == "USA"}) as p
return p{*}
结果:p

查找Léon
和USA
之间的4步内路径,并剔除所有环路:
n({name == "Léon"}).e()[:4].n({name == "USA"}).no_circle() as p
return p{*}
结果:p

限制查询数量
查找每个导演执导的一部电影:
n({@director} as d).e().n({@movie} as m).limit(1)
return table(d.name,m.name)
结果:
d.name | m.name |
---|---|
James Cameron | The Terminator |
Luc Besson | Léon |
使用OPTIONAL
本条查询中,路径模板语句执行三次,每次使用c
中的一条记录。使用OPTIONAL
前缀后,如果没有查询到数据,则返回null
:
find().nodes({@country}) as c
optional n(c).e({@filmedIn}).n({@movie} as m)
return table(c.name, m.name)
结果:
c.name | m.name |
---|---|
France | Léon |
Canada | null |
USA | Léon |
USA | Avatar |
USA | The Terminator |
若不使用OPTIONAL
前缀,则没有关于Canada
的结果返回:
find().nodes({@country}) as c
n(c).e({@filmedIn}).n({@movie} as m)
return table(c.name, m.name)
结果:
c.name | m.name |
---|---|
France | Léon |
USA | Léon |
USA | Avatar |
USA | The Terminator |
示例图集2

在一个空图集中,逐行运行以下语句,创建示例图集:
create().node_schema("customer").node_schema("account").edge_schema("owns").edge_schema("transfers")
create().node_property(@account, "level", uint32).edge_property(@transfers, "time", datetime)
insert().into(@customer).nodes([{_id:"C01"}])
insert().into(@account).nodes([{_id:"A01", level: 2}, {_id:"A02", level: 3}, {_id:"A03", level: 4}, {_id:"A04", level: 2}])
insert().into(@owns).edges([{_from:"C01", _to:"A01"}, {_from:"C01", _to:"A02"}])
insert().into(@transfers).edges([{_from:"A01", _to:"A03", time:"2023-03-01"}, {_from:"A01", _to:"A04", time:"2023-04-25"}, {_from:"A03", _to:"A04", time:"2023-03-27"}, {_from:"A04", _to:"A02", time:"2023-02-15"}])
包含0步路径
查找C01
持有的账户与其他账户间的0到1步出向交易路径,其中其他账户的level
属性值不小于3:
n({_id == "C01"}).e().n({@account}).re({@transfers})[0:1].n({@account.level >= 3}) as p
return p
结果:p

[0:1]
表明遍历可以沿re({@transfers})
关系执行0
或1
步。当应用0
步时,re({@transfers})[0:1]
将被忽略,其前后的点将被合并,路径模板简化为n({_id == "C01"}).e().n({@account.level >= 3})
。
以下查询中,由于合并后的点n({@account.level < 3 && @account.level >= 3})
不存在,所以0
步不会生成任何结果:
n({_id == "C01"}).e().n({@account.level < 3}).re({@transfers})[0:1].n({@account.level >= 3}) as p
return p
结果:p

步间过滤
prev_n,prev_e
使用系统别名prev_n
和prev_e
可在路径模板中实现步间过滤,即在每一步引用前一个点或边。
查找账户之间的2步出向交易路径,其中time
属性递增:
n().re({@transfers.time > prev_e.time})[2].n() as p
return p
结果:p

了解更多prev_e
和prev_n
的使用细节,请参阅系统别名。
复用别名
本条查询通过再次使用路径模板中声明的别名,可达成与上述相同的结果:
n().re({@transfers} as t1).n().re({@transfers.time > t1.time}).n() as p
return p
结果:p
