概述
使用K邻模板khop().n()...n()
会按照定义的路径模板获取路径中多个起点的K邻。K值由符合路径模板的最短路径长度决定。与此同时,返回的K步邻居必须符合路径模板中最后一个n()
中设定的条件。
K邻 vs. K邻模板
与K邻相比,K邻模板在定义最短路径查询K邻时更为灵活:
K邻 | K邻模板 | |
---|---|---|
K值 | 由depth() 方法定义 |
由路径模板定义 |
边过滤 | 使用方法edge_filter() 和direction() 对所有边统一应用过滤条件 |
可针对每条边设置不同过滤条件 |
邻居点过滤 | 使用方法node_filter() 对所有点统一应用过滤条件 |
可针对每个点设置不同过滤条件 |
路径模板 vs. K邻模板
实现相同查询目的时,K邻模板往往比路径模板的查询效率高。
例如,以下两条查询均获取某用户点击的不同ads
数量,返回结果相同。然而,K邻模板查询更加高效,在大型图集上尤为明显。
n({_id == "u316"}).e({@clicks}).n({@ad} as ads)
return count(DISTINCT ads)
khop().n({_id == "u316"}).e({@clicks}).n({@ad}) as ads
with count(ads)
此外,路径模板返回的终点没有去重,因此需要使用DISTINCT
。相反,K邻模板返回的结果已自动去重,确保不论涉及多少条边,每个终点仅出现一次。
请注意,二者的语句别名类型不同:路径模板的语句别名类型为PATH
;而K邻模板的语句别名类型为NODE
。
语法
- 语句别名:类型为
NODE
- 在路径模板中:
- 首个点模板
n()
必须包含有效过滤条件(包裹在{}
中)或别名引用,以指定遍历起点。 - 边模板
e()[<steps>]
和e().nf()[<steps>]
不支持在[<steps>]
中使用[*:N]
格式,这是因为K邻模板本质上遍历所有最短路径。 - 当
[<steps>]
包含0
步路径时,语句将返回遍历起点及其K步邻居。 - 不支持任何形式的步间过滤,包括使用系统别名(
prev_n
,prev_e
)或复用别名。
- 首个点模板
- 可在路径模板后串联使用的方法:
方法 |
参数 |
描述 | 可选 |
别名类型 |
---|---|---|---|---|
limit() |
<N> |
限制每个起点返回的K邻数量(N ≥-1);-1 表示返回所有邻居 |
是 | N/A |
示例图集

在一个空图集中,逐行运行以下语句,创建示例图集:
create().edge_property(@default, "weight", int32)
insert().into(@default).nodes([{_id:"A"}, {_id:"B"}, {_id:"C"}, {_id:"D"}, {_id:"E"}, {_id:"F"}])
insert().into(@default).edges([{_from:"A", _to:"C", weight:1}, {_from:"E", _to:"B", weight:1}, {_from:"A", _to:"E", weight:4}, {_from:"D", _to:"C", weight:2}, {_from:"E", _to:"D", weight:3}, {_from:"B", _to:"A", weight:2}, {_from:"F", _to:"A", weight:4}])
查找K步邻居
N步内邻居
查找点A
的1到2步邻居:
khop().n({_id == "A"}).e()[:2].n() as n
return collect(n._id)
结果:
collect(n._id) |
---|
["C","F","E","B","D"] |
N步邻居
查找点A
的2步邻居:
khop().n({_id == "A"}).e()[2].n() as n
return collect(n._id)
结果:
collect(n._id) |
---|
["D"] |
N到M步邻居
查找点D
的2到3步邻居:
khop().n({_id == "D"}).e()[2:3].n() as n
return collect(n._id)
结果:
collect(n._id) |
---|
["A","B","F"] |
过滤邻居
查找点D
的2步邻居,且在每条最短路径中,第一步不经过点C
,第二步不经过点A
:
khop().n({_id == "D"}).e().n({_id != "C"}).e().n({_id != "A"}) as n
return collect(n._id)
结果:
collect(n._id) |
---|
["B"] |
过滤边
查找点D
的2步邻居,要求每条最短路径的两条边分别指向右侧和左侧:
khop().n({_id == "D"}).re().n().le().n() as n
return collect(n._id)
结果:
collect(n._id) |
---|
["A"] |
返回起点
查找点D
的1步邻居同时返回点D
:
khop().n({_id == "D"}).e()[0:1].n() as n
return collect(n._id)
结果:
collect(n._id) |
---|
["D","E","C"] |
限制查询数量
分别查找点A
和点D
的1到2步邻居,每个点仅返回一个邻居:
khop().n({_id in ["D", "A"]}).e()[:2].n().limit(1) as n
return collect(n._id)
结果:
collect(n._id) |
---|
["E","C"] |
使用OPTIONAL
本条查询中,khop().n()...n()
语句执行两次,每次使用start
中的一条记录。使用OPTIONAL
前缀后,如果没有查询到数据,则返回null
:
find().nodes({_id in ["A", "D"]}) as start
optional khop().n(start).re()[2].n() as n
return table(start._id, n._id)
结果:
start._id | n._id |
---|---|
D | null |
A | D |
A | B |
若不使用OPTIONAL
前缀,则没有关于点D
的结果返回:
find().nodes({_id in ["A", "D"]}) as start
khop().n(start).re()[2].n() as n
return table(start._id, n._id)
结果:
start._id | n._id |
---|---|
A | D |
A | B |