基本工作流程
图论中最常见的问题之一是寻找节点之间的最短路径。本示例展示了如何从 Neo4j 数据创建 GDS 图、运行路径查找算法,并将结果写回 Neo4j。
创建图
以下 Cypher 查询在 Neo4j 数据库中创建了一个小型列车网络图。每条关系都包含一个 distance 数值属性,代表两个车站之间的距离。
CREATE
// Add the stations
(a:Station {name: 'Kings Cross'}),
(b:Station {name: 'Euston'}),
(c:Station {name: 'Camden Town'}),
(d:Station {name: 'Mornington Crescent'}),
(e:Station {name: 'Kentish Town'}),
// Add the connections between stations
(a)-[:CONNECTION {distance: 0.7}]->(b),
(b)-[:CONNECTION {distance: 1.3}]->(c),
(b)-[:CONNECTION {distance: 0.7}]->(d),
(d)-[:CONNECTION {distance: 0.6}]->(c),
(c)-[:CONNECTION {distance: 1.3}]->(e)
该图如下所示
接下来的查询从 :Station 节点和具有 distance 属性的 :CONNECTION 关系创建了一个名为 trainGraph 的内存图。
MATCH (source:Station)-[r:CONNECTION]->(target:Station)
RETURN gds.graph.project(
'trainGraph',
source,
target,
{ relationshipProperties: r { .distance } }
)
在 stream(流)模式下运行算法
计算图中最短路径的一个很好的首选算法是 Dijkstra 源-目标最短路径算法。要尝试该算法,请使用 stream 模式,以便在查询输出中查看结果。
MATCH (1)
(source:Station {name: 'Kings Cross'}),
(target:Station {name: 'Kentish Town'})
CALL gds.shortestPath.dijkstra.stream( (2)
'trainGraph', (3)
{ (4)
sourceNode: source,
targetNode: target,
relationshipWeightProperty: 'distance'
}
)
YIELD (5)
index,
sourceNode,
targetNode,
totalCost,
path
RETURN (6)
index,
gds.util.asNode(sourceNode).name AS sourceNodeName,
gds.util.asNode(targetNode).name AS targetNodeName,
totalCost,
nodes(path) AS path
ORDER BY index
| 1 | 用于定义源节点和目标节点的 MATCH 子句。 |
| 2 | 在 stream 模式下运行的 gds.shortestPath.dijkstra 算法。 |
| 3 | 运行该算法的投影图名称。 |
| 4 | 算法的 语法部分(Stream mode 面板)中列出的配置参数。 |
| 5 | 算法的 语法部分(Stream mode 面板)中列出的结果字段。仅包含您需要的字段。 |
| 6 | 查询结果字段,通常是 YIELD 子句中包装在 Cypher 函数中的结果字段。gds.util.asNode() 函数用于检索与投影节点对应的 Neo4j 节点。对于路径查找算法,Cypher 的 nodes() 函数非常有用,它将节点路径作为节点列表返回。 |
| index | sourceNodeName | targetNodeName | totalCost | path |
|---|---|---|---|---|
0 |
"Kings Cross"(国王十字车站) |
"Kentish Town"(肯蒂什镇车站) |
3.3 |
[Node[0], Node[1], Node[2], Node[4]] |
写入结果
如果算法结果符合预期,下一步可以是将其写回 Neo4j 数据库。以下查询与 stream 查询非常相似,区别在于增加了特定于 write 模式的配置参数,并且结果格式不同。
MATCH (1)
(source:Station {name: 'Kings Cross'}),
(target:Station {name: 'Kentish Town'})
CALL gds.shortestPath.dijkstra.write( (2)
'trainGraph', (3)
{ (4)
sourceNode: source,
targetNode: target,
relationshipWeightProperty: 'distance',
writeRelationshipType: 'PATH',
writeNodeIds: true,
writeCosts: true
}
)
YIELD relationshipsWritten
RETURN relationshipsWritten
| 1 | 用于定义源节点和目标节点的 MATCH 子句。 |
| 2 | 在 write(写入)模式下运行的 gds.shortestPath.dijkstra 算法。 |
| 3 | 投影图的名称。 |
| 4 | 算法的 语法部分(Write mode 面板)中列出的配置参数。在这种情况下,使用 writeRelationshipType、writeNodeIds 和 writeCosts 这三个参数来创建新的 :PATH 关系及其 totalCost、nodeIds 和 costs 属性。 |
| relationshipsWritten |
|---|
1 |
查询 Neo4j 数据库
为验证算法结果已正确写回 Neo4j,您可以运行包含上一步写入的新关系和关系属性(在本例中为带有 nodeIds、costs 和 totalCost 属性的 PATH 关系)的 Cypher 查询。
MATCH (source)-[r:PATH]->(target)
RETURN
source.name,
[nodeId IN r.nodeIds | gds.util.asNode(nodeId).name] AS nodeNames,
r.costs,
r.totalCost,
target.name
| source.name | nodeNames | r.costs | r.totalCost | target.name |
|---|---|---|---|---|
"Kings Cross"(国王十字车站) |
["Kings Cross", "Euston", "Camden Town", "Kentish Town"] |
[0.0, 0.7, 2.0, 3.3] |
3.3 |
"Kentish Town"(肯蒂什镇车站) |
后续步骤
本示例涵盖了使用 GDS 算法的基础知识。下一个示例将展示一个完整的端到端工作流程,包括如何将一种算法的输出作为另一种算法的输入。