MATCH¶
The MATCH
statement provides pattern-based search functionality, allowing you to retrieve data that matches one or more patterns in NebulaGraph. By defining one or more patterns, you can search for data that matches the patterns in NebulaGraph. Once the matching data is retrieved, you can use the RETURN
clause to return it as a result.
The examples in this topic use the basketballplayer dataset as the sample dataset.
Syntax¶
The syntax of MATCH
is relatively more flexible compared with that of other query statements such as GO
or LOOKUP
. The path type of the MATCH
statement is trail
. That is, only vertices can be repeatedly visited in the graph traversal. Edges cannot be repeatedly visited. For details, see path. But generally, it can be summarized as follows.
MATCH <pattern> [<clause_1>] RETURN <output> [<clause_2>];
pattern
: TheMATCH
statement supports matching one or multiple patterns. Multiple patterns are separated by commas (,). For example:(a)-[]->(b),(c)-[]->(d)
. For the detailed description of patterns, see Patterns.
clause_1
: TheWHERE
,WITH
,UNWIND
, andOPTIONAL MATCH
clauses are supported, and theMATCH
clause can also be used.
output
: Define the list name for the output results to be returned. You can useAS
to set an alias for the list.
clause_2
: TheORDER BY
andLIMIT
clauses are supported.
Legacy version compatibility
- Starting from version 3.5.0, the
MATCH
statement supports full table scans. It can traverse vertices or edges in the graph without using any indexes or filter conditions. In previous versions, theMATCH
statement required an index for certain queries or needed to useLIMIT
to restrict the number of output results.
- Starting from NebulaGraph version 3.0.0, in order to distinguish the properties of different tags, you need to specify a tag name when querying properties. The original statement
RETURN <variable_name>.<property_name>
is changed toRETURN <variable_name>.<tag_name>.<property_name>
.
Notes¶
- Avoid full table scans, as they may result in decreased query performance, and if there is insufficient memory during a full table scan, the query may fail, and the system will report an error. It is recommended to use queries with filter conditions or specifying tags and edge types, such as
v:player
andv.player.name
in the statementMATCH (v:player) RETURN v.player.name AS Name
.
- You can create an index for a tag, edge type, or a specific property of a tag or edge type to improve query performance. For example, you can create an index for the
player
tag or the name property of theplayer
tag. For more information about the usage and considerations for indexes, see Must-read for using indexes.
- The
MATCH
statement cannot query dangling edges.
Using patterns in MATCH statements¶
Match vertices¶
You can use a user-defined variable in a pair of parentheses to represent a vertex in a pattern. For example: (v)
.
nebula> MATCH (v) \
RETURN v \
LIMIT 3;
+-----------------------------------------------------------+
| v |
+-----------------------------------------------------------+
| ("player102" :player{age: 33, name: "LaMarcus Aldridge"}) |
| ("player106" :player{age: 25, name: "Kyle Anderson"}) |
| ("player115" :player{age: 40, name: "Kobe Bryant"}) |
+-----------------------------------------------------------+
Match tags¶
Legacy version compatibility
- In NebulaGraph versions earlier than 3.0.0, the prerequisite for matching a tag is that the tag itself has an index or a certain property of the tag has an index.
- Starting from NebulaGraph 3.0.0, you can match tags without creating an index, but you need to use
LIMIT
to restrict the number of output results.
- Starting from NebulaGraph 3.5.0, the
MATCH
statement supports full table scans. There is no need to create an index for a tag or a specific property of a tag, nor useLIMIT
to restrict the number of output results in order to execute theMATCH
statement.
You can specify a tag with :<tag_name>
after the vertex in a pattern.
nebula> MATCH (v:player) \
RETURN v;
+---------------------------------------------------------------+
| v |
+---------------------------------------------------------------+
| ("player105" :player{age: 31, name: "Danny Green"}) |
| ("player109" :player{age: 34, name: "Tiago Splitter"}) |
| ("player111" :player{age: 38, name: "David West"}) |
...
To match vertices with multiple tags, use colons (:).
nebula> CREATE TAG actor (name string, age int);
nebula> INSERT VERTEX actor(name, age) VALUES "player100":("Tim Duncan", 42);
nebula> MATCH (v:player:actor) \
RETURN v \
+----------------------------------------------------------------------------------------+
| v |
+----------------------------------------------------------------------------------------+
| ("player100" :actor{age: 42, name: "Tim Duncan"} :player{age: 42, name: "Tim Duncan"}) |
+----------------------------------------------------------------------------------------+
Match vertex properties¶
Note
The prerequisite for matching a vertex property is that the tag itself has an index of the corresponding property. Otherwise, you cannot execute the MATCH
statement to match the property.
You can specify a vertex property with {<prop_name>: <prop_value>}
after the tag in a pattern.
# The following example uses the name property to match a vertex.
nebula> MATCH (v:player{name:"Tim Duncan"}) \
RETURN v;
+----------------------------------------------------+
| v |
+----------------------------------------------------+
| ("player100" :player{age: 42, name: "Tim Duncan"}) |
+----------------------------------------------------+
The WHERE
clause can do the same thing:
nebula> MATCH (v:player) \
WHERE v.player.name == "Tim Duncan" \
RETURN v;
+----------------------------------------------------+
| v |
+----------------------------------------------------+
| ("player100" :player{age: 42, name: "Tim Duncan"}) |
+----------------------------------------------------+
OpenCypher compatibility
In openCypher 9, =
is the equality operator. However, in nGQL, ==
is the equality operator and =
is the assignment operator (as in C++ or Java).
Use the WHERE
clause to directly get all the vertices with the vertex property value Tim Duncan.
nebula> MATCH (v) \
WITH v, properties(v) as props, keys(properties(v)) as kk \
WHERE [i in kk where props[i] == "Tim Duncan"] \
RETURN v;
+----------------------------------------------------+
| v |
+----------------------------------------------------+
| ("player100" :player{age: 42, name: "Tim Duncan"}) |
+----------------------------------------------------+
nebula> WITH ['Tim Duncan', 'Yao Ming'] AS names \
MATCH (v1:player)-->(v2:player) \
WHERE v1.player.name in names \
return v1, v2;
+----------------------------------------------------+----------------------------------------------------------+
| v1 | v2 |
+----------------------------------------------------+----------------------------------------------------------+
| ("player133" :player{age: 38, name: "Yao Ming"}) | ("player114" :player{age: 39, name: "Tracy McGrady"}) |
| ("player133" :player{age: 38, name: "Yao Ming"}) | ("player144" :player{age: 47, name: "Shaquille O'Neal"}) |
| ("player100" :player{age: 42, name: "Tim Duncan"}) | ("player101" :player{age: 36, name: "Tony Parker"}) |
| ("player100" :player{age: 42, name: "Tim Duncan"}) | ("player125" :player{age: 41, name: "Manu Ginobili"}) |
+----------------------------------------------------+----------------------------------------------------------+
Match VIDs¶
You can use the VID to match a vertex. The id()
function can retrieve the VID of a vertex.
nebula> MATCH (v) \
WHERE id(v) == 'player101' \
RETURN v;
+-----------------------------------------------------+
| v |
+-----------------------------------------------------+
| ("player101" :player{age: 36, name: "Tony Parker"}) |
+-----------------------------------------------------+
To match multiple VIDs, use WHERE id(v) IN [vid_list]
or WHERE id(v) IN {vid_list}
.
nebula> MATCH (v:player { name: 'Tim Duncan' })--(v2) \
WHERE id(v2) IN ["player101", "player102"] \
RETURN v2;
+-----------------------------------------------------------+
| v2 |
+-----------------------------------------------------------+
| ("player101" :player{age: 36, name: "Tony Parker"}) |
| ("player101" :player{age: 36, name: "Tony Parker"}) |
| ("player102" :player{age: 33, name: "LaMarcus Aldridge"}) |
+-----------------------------------------------------------+
nebula> MATCH (v) WHERE id(v) IN {"player100", "player101"} \
RETURN v.player.name AS name;
+---------------+
| name |
+---------------+
| "Tony Parker" |
| "Tim Duncan" |
+---------------+
Match connected vertices¶
You can use the --
symbol to represent edges of both directions and match vertices connected by these edges.
Legacy version compatibility
In nGQL 1.x, the --
symbol is used for inline comments. Starting from nGQL 2.x, the --
symbol represents an incoming or outgoing edge.
nebula> MATCH (v:player{name:"Tim Duncan"})--(v2) \
RETURN v2.player.name AS Name;
+---------------------+
| Name |
+---------------------+
| "Manu Ginobili" |
| "Manu Ginobili" |
| "Tiago Splitter" |
...
You can add a >
or <
to the --
symbol to specify the direction of an edge.
In the following example, -->
represents an edge that starts from v
and points to v2
. To v
, this is an outgoing edge, and to v2
this is an incoming edge.
nebula> MATCH (v:player{name:"Tim Duncan"})-->(v2:player) \
RETURN v2.player.name AS Name;
+-----------------+
| Name |
+-----------------+
| "Manu Ginobili" |
| "Tony Parker" |
+-----------------+
To query the properties of the target vertices, use the CASE
expression.
nebula> MATCH (v:player{name:"Tim Duncan"})--(v2) \
RETURN \
CASE WHEN v2.team.name IS NOT NULL \
THEN v2.team.name \
WHEN v2.player.name IS NOT NULL \
THEN v2.player.name END AS Name;
+---------------------+
| Name |
+---------------------+
| "Manu Ginobili" |
| "Manu Ginobili" |
| "Spurs" |
| "Dejounte Murray" |
...
To extend the pattern, you can add more vertices and edges.
nebula> MATCH (v:player{name:"Tim Duncan"})-->(v2)<--(v3) \
RETURN v3.player.name AS Name;
+---------------------+
| Name |
+---------------------+
| "Dejounte Murray" |
| "LaMarcus Aldridge" |
| "Marco Belinelli" |
...
If you do not need to refer to a vertex, you can omit the variable representing it in the parentheses.
nebula> MATCH (v:player{name:"Tim Duncan"})-->()<--(v3) \
RETURN v3.player.name AS Name;
+---------------------+
| Name |
+---------------------+
| "Dejounte Murray" |
| "LaMarcus Aldridge" |
| "Marco Belinelli" |
...
Match paths¶
Connected vertices and edges form a path. You can use a user-defined variable to name a path as follows.
nebula> MATCH p=(v:player{name:"Tim Duncan"})-->(v2) \
RETURN p;
+--------------------------------------------------------------------------------------------------------------------------------------+
| p |
+--------------------------------------------------------------------------------------------------------------------------------------+
| <("player100" :player{age: 42, name: "Tim Duncan"})-[:serve@0 {end_year: 2016, start_year: 1997}]->("team204" :team{name: "Spurs"})> |
| <("player100" :player{age: 42, name: "Tim Duncan"})-[:follow@0 {degree: 95}]->("player101" :player{age: 36, name: "Tony Parker"})> |
| <("player100" :player{age: 42, name: "Tim Duncan"})-[:follow@0 {degree: 95}]->("player125" :player{age: 41, name: "Manu Ginobili"})> |
+--------------------------------------------------------------------------------------------------------------------------------------+
OpenCypher compatibility
In nGQL, the @
symbol represents the rank of an edge, but openCypher has no such concept.
Match edges¶
nebula> MATCH ()<-[e]-() \
RETURN e \
LIMIT 3;
+----------------------------------------------------+
| e |
+----------------------------------------------------+
| [:follow "player101"->"player102" @0 {degree: 90}] |
| [:follow "player103"->"player102" @0 {degree: 70}] |
| [:follow "player135"->"player102" @0 {degree: 80}] |
+----------------------------------------------------+
Match edge types¶
Just like vertices, you can specify edge types with :<edge_type>
in a pattern. For example: -[e:follow]-
.
OpenCypher compatibility
- In NebulaGraph versions earlier than 3.0.0, the prerequisite for matching a edge type is that the edge type itself has an index or a certain property of the edge type has an index.
- Starting from version 3.0.0, there is no need to create an index for matching a edge type, but you need to use
LIMIT
to limit the number of output results and you must specify the direction of the edge.
- Starting from NebulaGraph 3.5.0, you can use the
MATCH
statement to match edges without creating an index for edge type or usingLIMIT
to restrict the number of output results.
nebula> MATCH ()-[e:follow]->() \
RETURN e;
+----------------------------------------------------+
| e |
+----------------------------------------------------+
| [:follow "player102"->"player100" @0 {degree: 75}] |
| [:follow "player102"->"player101" @0 {degree: 75}] |
| [:follow "player129"->"player116" @0 {degree: 90}] |
...
Match edge type properties¶
Note
The prerequisite for matching an edge type property is that the edge type itself has an index of the corresponding property. Otherwise, you cannot execute the MATCH
statement to match the property.
You can specify edge type properties with {<prop_name>: <prop_value>}
in a pattern. For example: [e:follow{likeness:95}]
.
nebula> MATCH (v:player{name:"Tim Duncan"})-[e:follow{degree:95}]->(v2) \
RETURN e;
+--------------------------------------------------------+
| e |
+--------------------------------------------------------+
| [:follow "player100"->"player101" @0 {degree: 95}] |
| [:follow "player100"->"player125" @0 {degree: 95}] |
+--------------------------------------------------------+
Use the WHERE
clause to directly get all the edges with the edge property value 90.
nebula> MATCH ()-[e]->() \
WITH e, properties(e) as props, keys(properties(e)) as kk \
WHERE [i in kk where props[i] == 90] \
RETURN e;
+----------------------------------------------------+
| e |
+----------------------------------------------------+
| [:follow "player125"->"player100" @0 {degree: 90}] |
| [:follow "player140"->"player114" @0 {degree: 90}] |
| [:follow "player133"->"player144" @0 {degree: 90}] |
| [:follow "player133"->"player114" @0 {degree: 90}] |
...
+----------------------------------------------------+
Match multiple edge types¶
The |
symbol can help matching multiple edge types. For example: [e:follow|:serve]
. The English colon (:) before the first edge type cannot be omitted, but the English colon before the subsequent edge type can be omitted, such as [e:follow|serve]
.
nebula> MATCH (v:player{name:"Tim Duncan"})-[e:follow|:serve]->(v2) \
RETURN e;
+---------------------------------------------------------------------------+
| e |
+---------------------------------------------------------------------------+
| [:follow "player100"->"player101" @0 {degree: 95}] |
| [:follow "player100"->"player125" @0 {degree: 95}] |
| [:serve "player100"->"team204" @0 {end_year: 2016, start_year: 1997}] |
+---------------------------------------------------------------------------+
Match multiple edges¶
You can extend a pattern to match multiple edges in a path.
nebula> MATCH (v:player{name:"Tim Duncan"})-[]->(v2)<-[e:serve]-(v3) \
RETURN v2, v3;
+----------------------------------+-----------------------------------------------------------+
| v2 | v3 |
+----------------------------------+-----------------------------------------------------------+
| ("team204" :team{name: "Spurs"}) | ("player104" :player{age: 32, name: "Marco Belinelli"}) |
| ("team204" :team{name: "Spurs"}) | ("player101" :player{age: 36, name: "Tony Parker"}) |
| ("team204" :team{name: "Spurs"}) | ("player102" :player{age: 33, name: "LaMarcus Aldridge"}) |
...
Match fixed-length paths¶
You can use the :<edge_type>*<hop>
pattern to match a fixed-length path. hop
must be a non-negative integer.
nebula> MATCH p=(v:player{name:"Tim Duncan"})-[e:follow*2]->(v2) \
RETURN DISTINCT v2 AS Friends;
+-----------------------------------------------------------+
| Friends |
+-----------------------------------------------------------+
| ("player100" :player{age: 42, name: "Tim Duncan"}) |
| ("player125" :player{age: 41, name: "Manu Ginobili"}) |
| ("player102" :player{age: 33, name: "LaMarcus Aldridge"}) |
+-----------------------------------------------------------+
If hop
is 0, the pattern will match the source vertex of the path.
nebula> MATCH (v:player{name:"Tim Duncan"}) -[*0]-> (v2) \
RETURN v2;
+----------------------------------------------------+
| v2 |
+----------------------------------------------------+
| ("player100" :player{age: 42, name: "Tim Duncan"}) |
+----------------------------------------------------+
Note
When you conditionally filter on multi-hop edges, such as -[e:follow*2]->
, note that the e
is a list of edges instead of a single edge.
For example, the following statement is correct from the syntax point of view which may not get your expected query result, because the e
is a list without the .degree
property.
nebula> MATCH p=(v:player{name:"Tim Duncan"})-[e:follow*2]->(v2) \
WHERE e.degree > 1 \
RETURN DISTINCT v2 AS Friends;
The correct statement is as follows:
nebula> MATCH p=(v:player{name:"Tim Duncan"})-[e:follow*2]->(v2) \
WHERE ALL(e_ in e WHERE e_.degree > 0) \
RETURN DISTINCT v2 AS Friends;
Further, the following statement is for filtering the properties of the first-hop edge in multi-hop edges:
nebula> MATCH p=(v:player{name:"Tim Duncan"})-[e:follow*2]->(v2) \
WHERE e[0].degree > 98 \
RETURN DISTINCT v2 AS Friends;
Match variable-length paths¶
You can use the :<edge_type>*[minHop..maxHop]
pattern to match variable-length paths.minHop
and maxHop
are optional and default to 1 and infinity respectively.
Caution
If maxHop
is not set, it may cause the Graph service to OOM. Execute this command with caution.
Parameter | Description |
---|---|
minHop |
Optional. minHop indicates the minimum length of the path, which must be a non-negative integer. The default value is 1. |
maxHop |
Optional. maxHop indicates the maximum length of the path, which must be a non-negative integer. The default value is infinity. |
If neither minHop
nor maxHop
is specified, and only :<edge_type>*
is set, the default values are applied to both, i.e., minHop
is 1 and maxHop
is infinity.
nebula> MATCH p=(v:player{name:"Tim Duncan"})-[e:follow*]->(v2) \
RETURN v2 AS Friends;
+-----------------------------------------------------------+
| Friends |
+-----------------------------------------------------------+
| ("player125" :player{age: 41, name: "Manu Ginobili"}) |
| ("player101" :player{age: 36, name: "Tony Parker"}) |
...
nebula> MATCH p=(v:player{name:"Tim Duncan"})-[e:follow*1..3]->(v2) \
RETURN v2 AS Friends;
+-----------------------------------------------------------+
| Friends |
+-----------------------------------------------------------+
| ("player101" :player{age: 36, name: "Tony Parker"}) |
| ("player125" :player{age: 41, name: "Manu Ginobili"}) |
| ("player100" :player{age: 42, name: "Tim Duncan"}) |
...
nebula> MATCH p=(v:player{name:"Tim Duncan"})-[e:follow*1..]->(v2) \
RETURN v2 AS Friends;
+-----------------------------------------------------------+
| Friends |
+-----------------------------------------------------------+
| ("player125" :player{age: 41, name: "Manu Ginobili"}) |
| ("player101" :player{age: 36, name: "Tony Parker"}) |
| ("player100" :player{age: 42, name: "Tim Duncan"}) |
...
You can use the DISTINCT
keyword to aggregate duplicate results.
nebula> MATCH p=(v:player{name:"Tim Duncan"})-[e:follow*1..3]->(v2:player) \
RETURN DISTINCT v2 AS Friends, count(v2);
+-----------------------------------------------------------+-----------+
| Friends | count(v2) |
+-----------------------------------------------------------+-----------+
| ("player102" :player{age: 33, name: "LaMarcus Aldridge"}) | 1 |
| ("player100" :player{age: 42, name: "Tim Duncan"}) | 4 |
| ("player101" :player{age: 36, name: "Tony Parker"}) | 3 |
| ("player125" :player{age: 41, name: "Manu Ginobili"}) | 3 |
+-----------------------------------------------------------+-----------+
If minHop
is 0
, the pattern will match the source vertex of the path. Compared to the preceding statement, the following example uses 0
as the minHop
. So in the following result set, "Tim Duncan"
is counted one more time than it is in the preceding result set because it is the source vertex.
nebula> MATCH p=(v:player{name:"Tim Duncan"})-[e:follow*0..3]->(v2:player) \
RETURN DISTINCT v2 AS Friends, count(v2);
+-----------------------------------------------------------+-----------+
| Friends | count(v2) |
+-----------------------------------------------------------+-----------+
| ("player102" :player{age: 33, name: "LaMarcus Aldridge"}) | 1 |
| ("player100" :player{age: 42, name: "Tim Duncan"}) | 5 |
| ("player125" :player{age: 41, name: "Manu Ginobili"}) | 3 |
| ("player101" :player{age: 36, name: "Tony Parker"}) | 3 |
+-----------------------------------------------------------+-----------+
Note
When using the variable e
to match fixed-length or variable-length paths in a pattern, such as -[e:follow*0..3]->
, it is not supported to reference e
in other patterns. For example, the following statement is not supported.
nebula> MATCH (v:player)-[e:like*1..3]->(n) \
WHERE (n)-[e*1..4]->(:player) \
RETURN v;
Match variable-length paths with multiple edge types¶
You can specify multiple edge types in a fixed-length or variable-length pattern. In this case, hop
, minHop
, and maxHop
take effect on all edge types.
nebula> MATCH p=(v:player{name:"Tim Duncan"})-[e:follow|serve*2]->(v2) \
RETURN DISTINCT v2;
+-----------------------------------------------------------+
| v2 |
+-----------------------------------------------------------+
| ("team204" :team{name: "Spurs"}) |
| ("player100" :player{age: 42, name: "Tim Duncan"}) |
| ("team215" :team{name: "Hornets"}) |
| ("player125" :player{age: 41, name: "Manu Ginobili"}) |
| ("player102" :player{age: 33, name: "LaMarcus Aldridge"}) |
+-----------------------------------------------------------+
Match multiple patterns¶
You can separate multiple patterns with commas (,).
nebula> CREATE TAG INDEX IF NOT EXISTS team_index ON team(name(20));
nebula> REBUILD TAG INDEX team_index;
nebula> MATCH (v1:player{name:"Tim Duncan"}), (v2:team{name:"Spurs"}) \
RETURN v1,v2;
+----------------------------------------------------+----------------------------------+
| v1 | v2 |
+----------------------------------------------------+----------------------------------+
| ("player100" :player{age: 42, name: "Tim Duncan"}) | ("team204" :team{name: "Spurs"}) |
+----------------------------------------------------+----------------------------------+
Match shortest paths¶
The allShortestPaths
function can be used to find all shortest paths between two vertices.
nebula> MATCH p = allShortestPaths((a:player{name:"Tim Duncan"})-[e*..5]-(b:player{name:"Tony Parker"})) \
RETURN p;
+------------------------------------------------------------------------------------------------------------------------------------+
| p |
+------------------------------------------------------------------------------------------------------------------------------------+
| <("player100" :player{age: 42, name: "Tim Duncan"})<-[:follow@0 {degree: 95}]-("player101" :player{age: 36, name: "Tony Parker"})> |
| <("player100" :player{age: 42, name: "Tim Duncan"})-[:follow@0 {degree: 95}]->("player101" :player{age: 36, name: "Tony Parker"})> |
+------------------------------------------------------------------------------------------------------------------------------------+
The shortestPath
function can be used to find a single shortest path between two vertices.
nebula> MATCH p = shortestPath((a:player{name:"Tim Duncan"})-[e*..5]-(b:player{name:"Tony Parker"})) \
RETURN p;
+------------------------------------------------------------------------------------------------------------------------------------+
| p |
+------------------------------------------------------------------------------------------------------------------------------------+
| <("player100" :player{age: 42, name: "Tim Duncan"})<-[:follow@0 {degree: 95}]-("player101" :player{age: 36, name: "Tony Parker"})> |
+------------------------------------------------------------------------------------------------------------------------------------+
Retrieve with multiple match¶
Multiple MATCH
can be used when different patterns have different filtering criteria and return the rows that exactly match the pattern.
nebula> MATCH (m)-[]->(n) WHERE id(m)=="player100" \
MATCH (n)-[]->(l) WHERE id(n)=="player125" \
RETURN id(m),id(n),id(l);
+-------------+-------------+-------------+
| id(m) | id(n) | id(l) |
+-------------+-------------+-------------+
| "player100" | "player125" | "team204" |
| "player100" | "player125" | "player100" |
+-------------+-------------+-------------+
Retrieve with optional match¶
See OPTIONAL MATCH.
Caution
In NebulaGraph, the performance and resource usage of the MATCH
statement have been optimized. But we still recommend to use GO
, LOOKUP
, |
, and FETCH
instead of MATCH
when high performance is required.