入门

本节包含一个入门部分,涵盖使用 Cypher® 查询进行图模式匹配的一些基本功能。

示例图

本教程中使用的示例图是火车 Stations 的模型,以及在 Stations 停靠的不同火车服务 Stops

patterns primer

要重新创建该图,请对空的 Neo4j 数据库运行以下查询

查询
CREATE (n1:Station {name: 'Denmark Hill'}),
(n5:Station {name: 'Battersea Park'}),
(n6:Station {name: 'Wandsworth Road'}),
(n15:Station {name: 'Clapham High Street'}),
(n16:Station {name: 'Peckham Rye'}),
(n17:Station {name: 'Brixton'}),
(n14:Station {name: 'London Victoria'}),
(n18:Station {name: 'Clapham Junction'}),
(p10:Stop {departs: time('22:37'), arrives: time('22:36')}),
(p0:Stop {departs: time('22:41'), arrives: time('22:41')}),
(p2:Stop {departs: time('22:43'), arrives: time('22:43')}),
(p17:Stop {arrives: time('22:50'), departs: time('22:50')}),
(p18:Stop {arrives: time('22:46'), departs: time('22:46')}),
(p19:Stop {departs: time('22:33'), arrives: time('22:31')}),
(p21:Stop {arrives: time('22:55')}),
(p20:Stop {departs: time('22:44'), arrives: time('22:43')}),
(p22:Stop {arrives: time('22:55')}),
(p23:Stop {arrives: time('22:48')}),
(n15)-[:LINK {distance: 1.96}]->(n1)-[:LINK {distance: 0.86}]->(n16),
(n15)-[:LINK {distance: 0.39}]->(n6)<-[:LINK {distance: 0.7}]-(n5)-[:LINK {distance: 1.24}]->(n14), (n5)-[:LINK {distance: 1.45}]->(n18),
(n14)<-[:LINK {distance: 3.18}]-(n17)-[:LINK {distance: 1.11}]->(n1),
(p2)-[:CALLS_AT]->(n6), (p17)-[:CALLS_AT]->(n5), (p19)-[:CALLS_AT]->(n16),
(p22)-[:CALLS_AT]->(n14), (p18)-[:CALLS_AT]->(n18), (p0)-[:CALLS_AT]->(n15), (p23)-[:CALLS_AT]->(n5), (p20)-[:CALLS_AT]->(n1),
(p21)-[:CALLS_AT]->(n14), (p10)-[:CALLS_AT]->(n1), (p19)-[:NEXT]->(p10)-[:NEXT]->(p0)-[:NEXT]->(p2)-[:NEXT]->(p23),
(p22)<-[:NEXT]-(p17)<-[:NEXT]-(p18), (p21)<-[:NEXT]-(p20)

匹配固定长度路径

一对空括号是一个 节点模式,它将匹配任何节点。此示例获取图中所有节点的计数

MATCH ()
RETURN count(*) AS numNodes
表 1. 结果
numNodes

18

行数:1

在节点模式中添加标签将过滤具有该标签的节点(请参阅 标签表达式)。以下查询获取所有具有标签 Stop 的节点的计数

MATCH (:Stop)
RETURN count(*) AS numStops
表 2. 结果
numStops

10

行数:1

路径模式 可以匹配关系以及它们连接的节点。以下查询获取所有停靠在 Denmark Hill 的火车的到达时间

MATCH (s:Stop)-[:CALLS_AT]->(:Station {name: 'Denmark Hill'})
RETURN s.arrives AS arrivalTime
表 3. 结果
arrivalTime

"22:36:00Z"

"22:43:00Z"

行数:2

路径模式可以包含内联 WHERE 子句。以下查询获取从 Denmark Hill 出发的 22:37 服务的下一个停靠点

MATCH (n:Station {name: 'Denmark Hill'})<-[:CALLS_AT]-
        (s:Stop WHERE s.departs = time('22:37'))-[:NEXT]->
        (:Stop)-[:CALLS_AT]->(d:Station)
RETURN d.name AS nextCallingPoint
表 4. 结果
nextCallingPoint

"Clapham High Street"

行数:1

有关更多信息,请参阅 固定长度模式.

匹配可变长度路径

仅遍历具有指定类型的关系的可变长度路径可以使用 量化关系 匹配。在关系模式中声明的任何变量都将返回遍历的关系列表。以下查询返回通过连接车站 Peckham RyeClapham Junction 的所有 LINK 行驶的总距离

查询
MATCH (:Station {name: 'Peckham Rye'})-[link:LINK]-+
        (:Station {name: 'Clapham Junction'})
RETURN reduce(acc = 0.0, l IN link | round(acc + l.distance, 2)) AS
         totalDistance
表 5. 结果
totalDistance

7.84

5.36

行数:2

-[:LINK]-+ 是一个 量化关系。它由关系模式 -[:LINK]- 组成,它匹配任何方向的关系,以及量词 +,它表示将匹配一个或多个关系。由于量化关系中不包含节点模式,因此它们将匹配任何中间节点。

可变长度路径也可以使用 量化路径模式 匹配,它允许 WHERE 子句以及访问路径遍历的节点。以下查询返回从 Peckham RyeLondon Victoria 的路线上的停靠点列表,其中车站之间的距离不超过两英里

查询
MATCH (:Station {name: 'Peckham Rye'})
      (()-[link:LINK]-(s) WHERE link.distance <= 2)+
      (:Station {name: 'London Victoria'})
UNWIND s AS station
RETURN station.name AS callingPoint
表 6. 结果
callingPoint

"Denmark Hill"

"Clapham High Street"

"Wandsworth Road"

"Battersea Park"

"London Victoria"

行数:5

节点模式内的 WHERE 子句本身可以包含路径模式。以下查询使用 EXISTS 子查询 锚定在 Stops 序列中的最后一个 Stop 上,并返回所有停靠在 Denmark Hill 的服务的出发时间、到达时间和最终目的地

查询
MATCH (:Station {name: 'Denmark Hill'})<-[:CALLS_AT]-(s1:Stop)-[:NEXT]->+
        (sN:Stop WHERE NOT EXISTS { (sN)-[:NEXT]->(:Stop) })-[:CALLS_AT]->
        (d:Station)
RETURN s1.departs AS departure, sN.arrives AS arrival,
       d.name AS finalDestination
表 7. 结果
departure arrival finalDestination

'22:37:00Z'

'22:48:00Z'

"Battersea Park"

'22:44:00Z'

'22:55:00Z'

"London Victoria"

行数:2

在量化路径模式内声明的节点变量将绑定到节点列表,这些节点列表可以被展开并在后续 MATCH 子句中使用。以下查询列出了从 Peckham RyeBattersea Park 火车服务的停靠点

查询
MATCH (:Station {name: 'Peckham Rye'})<-[:CALLS_AT]-(:Stop)
      (()-[:NEXT]->(s:Stop))+
      ()-[:CALLS_AT]->(:Station {name: 'Battersea Park'})
UNWIND s AS stop
MATCH (stop)-[:CALLS_AT]->(station:Station)
RETURN stop.arrives AS arrival, station.name AS callingPoint
表 8. 结果
arrival callingPoint

"22:36:00Z"

"Denmark Hill"

"22:41:00Z"

"Clapham High Street"

"22:43:00Z"

"Wandsworth Road"

"22:48:00Z"

"Battersea Park"

行数:4

在路径模式中重复节点变量使同一个节点可以在路径中绑定多次(请参阅 等值连接)。以下查询找到所有由 Stations 之间的 LINK 形成的循环(即,通过同一个 Station 多次)中的车站

查询
MATCH (n:Station)-[:LINK]-+(n)
RETURN DISTINCT n.name AS station
表 9. 结果
station

"Denmark Hill"

"Battersea Park"

"Wandsworth Road"

"Clapham High Street"

"Brixton"

"London Victoria"

行数:6

可以使用 图模式 匹配复杂的非线性路径,图模式是通过重复的节点变量(即等值连接)连接的路径模式的逗号分隔列表。例如,一名乘客从 Denmark Hill 出发,想要搭乘从 Clapham Junction 出发的 22:46London Victoria 的火车服务。以下查询找到从 Denmark Hill 出发的出发时间,以及换乘 Station 和到达时间

查询
MATCH (:Station {name: 'Denmark Hill'})<-[:CALLS_AT]-
        (s1:Stop)-[:NEXT]->+(s2:Stop)-[:CALLS_AT]->
        (c:Station)<-[:CALLS_AT]-(x:Stop),
       (:Station {name: 'Clapham Junction'})<-[:CALLS_AT]-
         (t1:Stop)-[:NEXT]->+(x)-[:NEXT]->+(:Stop)-[:CALLS_AT]->
         (:Station {name: 'London Victoria'})
WHERE t1.departs = time('22:46')
      AND s2.arrives < x.departs
RETURN s1.departs AS departure, s2.arrives AS changeArrival,
       c.name AS changeAt
表 10. 结果
departure changeArrival changeAt

"22:37:00Z"

"22:48:00Z"

"Battersea Park"

行数:1

有关更多信息,请参阅 可变长度模式.

匹配最短路径

可以使用 SHORTEST 关键字查找两个节点之间的最短路径

查询
MATCH p = SHORTEST 1
  (:Station {name: "Brixton"})
  (()-[:LINK]-(:Station))+
  (:Station {name: "Clapham Junction"})
RETURN [station IN nodes(p) | station.name] AS route
表 11. 结果
route

["Brixton", "London Victoria", "Battersea Park", "Clapham Junction"]

行数:1

要查找所有最短路径,可以使用 ALL SHORTEST 关键字

查询
MATCH p = ALL SHORTEST
  (:Station {name: "Denmark Hill"})
  (()-[:LINK]-(:Station))+
  (:Station {name: "Clapham Junction"})
RETURN [station IN nodes(p) | station.name] AS route
表 12. 结果
route

["Denmark Hill", "Clapham High Street", "Wandsworth Road", "Battersea Park", "Clapham Junction"]

["Denmark Hill", "Brixton", "London Victoria", "Battersea Park", "Clapham Junction"]

行数:2

通常,SHORTEST k 可用于返回 k 个最短路径。以下返回两个最短路径

查询
MATCH p = SHORTEST 2
  (:Station {name: "Denmark Hill"})
  (()-[:LINK]-(:Station))+
  (:Station {name: "Clapham High Street"})
RETURN [station IN nodes(p) | station.name] AS route
表 13. 结果
route

["Denmark Hill", "Clapham High Street"]

["Denmark Hill", "Brixton", "London Victoria", "Battersea Park", "Wandsworth Road", "Clapham High Street"]

行数:2

有关更多信息,请参阅 最短路径.