Spanner Graph reference for openCypher users
Stay organized with collections
Save and categorize content based on your preferences.
This document compares openCypher and Spanner Graph in the following ways:
- Terminology
- Data model
- Schema
- Query
- Mutation
This document assumes you're familiar with openCypher v9.
Before you begin
Set up and query Spanner Graph using the Google Cloud console.
Terminology
openCypher | Spanner Graph |
---|---|
nodes | nodes |
relationships | edges |
node labels | node labels |
relationship types | edge labels |
clauses | Spanner Graph uses the term statement for a complete unit of
execution, and clause for a modifier to statements.For example, MATCH is a statement whereas
WHERE is a clause. |
relationship uniqueness openCypher doesn't return results with repeating edges in a single match. |
TRAIL pathWhen uniqueness is desired in Spanner Graph, use TRAIL mode to return unique edges in a single match.
|
Standards compliance
Spanner Graph adopts ISO Graph Query Language (GQL) and SQL/Property Graph Queries (SQL/PGQ) standards.
Data model
Both Spanner Graph and openCypher adopt the property graph data model with some differences.
openCypher | Spanner Graph |
---|---|
Each relationship has exactly one relationship type. |
Both nodes and edges have one or more labels. |
Schema
openCypher | Spanner Graph |
---|---|
A graph has no predefined schema. | A graph schema must be explicitly defined by using the
CREATE PROPERTY GRAPH statement.Labels are statically defined in the schema. To update labels, you need to update the schema. For more information, see Create, update, or drop a Spanner Graph schema. |
Query
Spanner Graph query capabilities are similar to those of openCypher. The differences between Spanner Graph and openCypher are described in this section.
Specify the graph
In openCypher, there is one default graph, and queries operate on the default
graph. In Spanner Graph, you can define more than one graph and a query
must start with the GRAPH
clause to specify the graph to query. For example:
GRAPHFinGraph
MATCH(p:Person)
RETURNp.name;
For more information, see the graph query syntax.
Graph pattern matching
Spanner Graph supports graph pattern matching capabilities similar to openCypher. The differences are explained in the following sections.
Relationship uniqueness and TRAIL mode
openCypher doesn't return results with repeating edges in a single match; this
is called relationship uniqueness in openCypher. In Spanner Graph,
repeating edges are returned by default. When uniqueness is desired, use
TRAIL
mode to ensure no repeating edge exists in the single match. For
detailed semantics of TRAIL
and other different path modes, see
Path mode.
The following example shows how the results of a query change with TRAIL
mode:
- The openCypher and Spanner Graph
TRAIL
mode queries return empty results because the only possible path is to repeatt1
twice. - By default, the Spanner Graph query returns a valid path.
Example graph
openCypher | Spanner Graph (TRAIL mode) | Spanner Graph (default mode) | ||||
---|---|---|---|---|---|---|
MATCH (src:Account)-[t1:Transfers]-> (dst:Account)-[t2:Transfers]-> (src)-[t1]->(dst) WHEREsrc.id=16 RETURNsrc.idASsrc_id,dst.idASdst_id; |
GRAPHFinGraph MATCHTRAIL (src:Account)-[t1:Transfers]-> (dst:Account)-[t2:Transfers]-> (src)-[t1]->(dst) WHEREsrc.id=16 RETURNsrc.idASsrc_id,dst.idASdst_id; |
GRAPHFinGraph MATCH (src:Account)-[t1:Transfers]-> (dst:Account)-[t2:Transfers]-> (src)-[t1]->(dst) WHEREsrc.id=16 RETURNsrc.idASsrc_id,dst.idASdst_id; |
||||
Empty result. | Empty result. | Result:
|
Return graph elements as query results
openCypher | Spanner Graph |
---|---|
MATCH(account:Account) WHEREaccount.id=16 RETURNaccount; |
GRAPHFinGraph MATCH(account:Account) WHEREaccount.id=16 RETURNTO_JSON(account)ASaccount; |
In Spanner Graph, query results don't return graph elements. Use the
TO_JSON
function to return graph elements as JSON.
Variable-length pattern matching and pattern quantification
Variable-length pattern matching in openCypher is called path quantification in Spanner Graph. Path quantification uses a different syntax, as shown in the following example. For more information, see Quantified path pattern.
openCypher | Spanner Graph |
---|---|
MATCH(src:Account)-[:Transfers*1..2]->(dst:Account) WHEREsrc.id=16 RETURNdst.id ORDERBYdst.id; |
GRAPHFinGraph MATCH(src:Account)-[:Transfers]->{1,2}(dst:Account) WHEREsrc.id=16 RETURNdst.id ORDERBYdst.id; |
Variable-length pattern: list of elements
Spanner Graph lets you directly access the variables used in path
quantifications. In the following example, e
in Spanner Graph is the same
as edges(p)
in openCypher.
openCypher | Spanner Graph |
---|---|
MATCHp=(src:Account)-[:Transfers*1..3]->(dst:Account) WHEREsrc.id=16 RETURNedges(p); |
GRAPHFinGraph MATCH(src:Account)-[e:Transfers]->{1,3}(dst:Account) WHEREsrc.id=16 RETURNTO_JSON(e)ASe; |
Shortest path
openCypher has two built-in functions to find the shortest path between nodes:
shortestPath
and allShortestPath
.
shortestPath
finds a single shortest path between nodes.allShortestPath
finds all the shortest paths between nodes. There can be multiple paths of the same length.
Spanner Graph uses a different syntax to find a single shortest path
between nodes: ANY SHORTEST
for shortestPath.
The allShortestPath
function isn't supported in Spanner Graph.
openCypher | Spanner Graph |
---|---|
MATCH (src:Account{id:7}), (dst:Account{id:20}), p=shortestPath((src)-[*1..10]->(dst)) RETURNlength(p)ASpath_length; |
GRAPHFinGraph MATCHANYSHORTEST (src:Account{id:7})-[e:Transfers]->{1,3} (dst:Account{id:20}) RETURNARRAY_LENGTH(e)ASpath_length; |
Statements and clauses
The following table lists the openCypher clauses, and indicates whether or not they're supported in Spanner Graph.
openCypher | Spanner Graph | |
---|---|---|
MATCH |
Supported. For more information, see graph pattern matching. | |
OPTIONAL MATCH |
Supported. For more information, see graph pattern matching. | |
RETURN / WITH |
Supported. For more information, see the
RETURN statement and the
WITH statement.
Spanner Graph requires explicit aliasing for complicated expressions. |
|
Supported. |
GRAPHFinGraph MATCH(p:Person) RETURNEXTRACT(YEARFROMp.birthday)ASbirthYear; |
|
Not supported. |
GRAPHFinGraph MATCH(p:Person) RETURNEXTRACT(YEARFROMp.birthday);-- No aliasing |
|
WHERE |
Supported. For more information, see the definition for graph pattern. | |
ORDER BY |
Supported. For more information, see the
ORDER BY statement. |
|
SKIP / LIMIT |
Supported. For more information, see the
SKIP statement and the
LIMIT statement.Spanner Graph requires a constant expression for the offset and the limit. |
|
Supported. |
GRAPHFinGraph MATCH(n:Account) RETURNn.id SKIP@offsetParameter LIMIT3; |
|
Not supported. |
GRAPHFinGraph MATCH(n:Account) RETURNn.id LIMITVALUE{ MATCH(m:Person) RETURNCOUNT(*)AScount }AScount;-- Not a constant expression |
|
UNION |
Supported. For more information, see Composite graph query. | |
UNION ALL |
Supported. For more information, see Composite graph query. | |
UNWIND |
Supported by FOR statement. |
|
GRAPHFinGraph LETarr=[1,2,3] FORnumINarr RETURNnum; |
||
MANDATORY MATCH |
Not supported. | |
CALL[YIELD...] |
Not supported. | |
CREATE , DELETE , SET ,
REMOVE , MERGE |
To learn more, see the Mutation section and Insert, update, or delete data in Spanner Graph. |
Data types
Spanner Graph supports all GoogleSQL data types. For more information, see Data types in GoogleSQL.
The following sections compare openCypher data types with Spanner Graph data types.
Structural type
openCypher | Spanner Graph |
---|---|
Node | Node |
Edge | Edge |
Path | Path |
Property type
openCypher | Spanner Graph |
---|---|
INT |
INT64 |
FLOAT |
FLOAT64 |
STRING |
STRING |
BOOLEAN |
BOOL |
LIST A homogeneous list of simple types. For example, List of INT , List of STRING .You can't mix INT and STRING in a single list. |
ARRAY |
Composite type
openCypher | Spanner Graph |
---|---|
LIST |
ARRAY or JSON |
MAP |
STRUCT or JSON |
Spanner Graph doesn't support heterogeneous lists of different types or maps of a dynamic key list and heterogeneous element value types. Use JSON for these use cases.
Type Coercion
openCypher | Spanner Graph |
---|---|
INT -> FLOAT |
Supported. |
For more information about type conversion rules, see Conversion rules in GoogleSQL.
Functions and expressions
Besides graph functions and expressions, Spanner Graph also supports all GoogleSQL built-in functions and expressions.
This section lists openCypher functions and expressions and their equivalents in Spanner Graph.
Structural type functions and expressions
Type | openCypher function or expression |
Spanner Graph function or expression |
|
---|---|---|---|
Node and Edge |
exists(n.prop) |
PROPERTY_EXISTS(n, prop) |
|
id (returns integer) |
Not supported. | ||
properties |
TO_JSON |
||
keys (property type names, but not property values) |
PROPERTY_NAMES |
||
labels |
LABELS |
||
Edge | endNode |
Not supported. | |
startNode |
Not supported. | ||
type |
LABELS |
||
Path | length |
Not supported. | |
nodes |
Not supported. | ||
relationships |
Not supported. | ||
Node and Edge | .
property reference |
. |
|
[]
dynamic property reference
|
Not supported. | ||
Pattern As Expression | size(pattern) |
Not supported. Use a subquery as following
|
Property type functions and expressions
Type | openCypher function or expression |
Spanner Graph function or expression |
|
---|---|---|---|
Scalar | coalesce |
COALESCE |
|
head |
ARRAY_FIRST |
||
last |
ARRAY_LAST |
||
size(list) |
ARRAY_LENGTH |
||
size(string) |
LENGTH |
||
timestamp |
UNIX_MILLIS(CURRENT_TIMESTAMP()) |
||
toBoolean /toFloat /toInteger |
CAST(expr AS type) |
||
Aggregate | avg |
AVG |
|
collect |
ARRAY_AGG |
||
count
| COUNT |
||
max |
MAX |
||
min |
MIN |
||
percentileCont |
PERCENTILE_CONT |
||
percentileDisc |
PERCENTILE_DISC |
||
stDev |
STDDEV |
||
stDevP |
Not supported. | ||
sum |
SUM |
||
List | range |
GENERATE_ARRAY |
|
reverse |
ARRAY_REVERSE |
||
tail |
Spanner Graph doesn't support tail .Use ARRAY_SLICE and ARRAY_LENGTH
instead. |
||
Mathematical | abs |
ABS |
|
ceil |
CEIL |
||
floor |
FLOOR |
||
rand |
RAND |
||
round |
ROUND |
||
sign |
SIGN |
||
e |
EXP(1) |
||
exp |
EXP |
||
log |
LOG |
||
log10 |
LOG10 |
||
sqrt |
SQRT |
||
acos |
ACOS |
||
asin |
ASIN |
||
atan |
ATAN |
||
atan2 |
ATAN2 |
||
cos |
COS |
||
cot |
COT |
||
degrees |
r * 90 / ASIN(1) |
||
pi |
ACOS(-1) |
||
radians |
d * ASIN(1) / 90 |
||
sin |
SIN |
||
tan |
TAN |
||
String | left |
LEFT |
|
ltrim |
LTRIM |
||
replace |
REPLACE |
||
reverse |
REVERSE |
||
right |
RIGHT |
||
rtrim |
RTRIM |
||
split |
SPLIT |
||
substring |
SUBSTR |
||
tolower |
LOWER |
||
tostring |
CAST(expr AS STRING) |
||
toupper |
UPPER |
||
trim |
TRIM |
||
DISTINCT | DISTINCT |
DISTINCT |
|
Mathematical | + |
+ |
|
- |
- |
||
* |
* |
||
/ |
/ |
||
% |
MOD |
||
^ |
POW |
||
Comparison | = |
= |
|
|
|
||
< |
< |
||
> |
> |
||
<= |
<= |
||
>= |
>= |
||
IS [NOT] NULL |
IS [NOT] NULL |
||
Chain of comparison
|
Spanner Graph
doesn't support a chain of comparison. This is equivalent to
comparisons conjuncted with AND . For example:
|
||
Boolean | AND |
AND |
|
OR |
OR |
||
XOR |
Spanner Graph
doesn't support XOR . Write the query with <> .For example:
|
||
NOT |
NOT |
||
String | STARTS WITH |
STARTS_WITH |
|
ENDS WITH |
ENDS_WITH |
||
CONTAINS |
REGEXP_CONTAINS |
||
+ |
CONCAT |
||
List | + |
ARRAY_CONCAT |
|
IN |
ARRAY_INCLUDES |
||
[] |
[] |
Other expressions
openCypher | Spanner Graph |
---|---|
Case expression | Supported. |
Exists subquery | Supported. |
Map projection | Not supported.STRUCT types provide similar functionalities. |
List comprehension | Not supported.GENERATE_ARRAY and ARRAY_TRANSFORM cover the majority of use cases. |
Query parameter
The following queries show the difference between using parameters in openCypher and in Spanner Graph.
openCypher | Spanner Graph | |
---|---|---|
Parameter | MATCH(n:Person) WHEREn.id=$id RETURNn.name; |
GRAPHFinGraph MATCH(n:Person) WHEREn.id=@id RETURNn.name; |
Mutation
Spanner Graph uses GoogleSQL DML to mutate the node and edge input tables. For more information, see Insert, update, or delete Spanner Graph data.
Create node and edge
openCypher | Spanner Graph | |
---|---|---|
Create nodes and edges | CREATE(:Person{id:100,name:'John'}); CREATE(:Account{id:1000,is_blocked:FALSE}); |
INSERTINTO Person(id,name) VALUES(100,"John"); |
Create nodes and edges with query results |
MATCH(a:Account{id:1}),(oa:Account) WHEREoaa CREATE(a)-[:Transfers{amount:100,create_time:timestamp()}]->(oa); |
INSERTINTOAccountTransferAccount(id,to_id,create_time,amount) SELECTa.id,oa.id,CURRENT_TIMESTAMP(),100 FROMGRAPH_TABLE( FinGraph MATCH (a:Account{id:1000}), (oa:Account) WHEREoaa ); |
In Spanner Graph, the labels are statically assigned according to the
CREATE PROPERTY GRAPH
DDL statement.
Update node and edge
openCypher | Spanner Graph | |
---|---|---|
Update properties | MATCH(p:Person{id:100}) SETp.country='United States'; |
UPDATEPersonASp SETp.country='United States' WHEREp.id=100; |
To update Spanner Graph labels, see Create, update, or drop a Spanner Graph schema.
Merge node and edge
openCypher | Spanner Graph | |
---|---|---|
Insert new element or update properties | MERGE(p:Person{id:100,country:'United States'}); |
INSERTORUPDATEINTOPerson (id,country) VALUES(100,'United States'); |
Delete node and edge
Deleting edges is the same as deleting the input table.
openCypher | Spanner Graph | |
---|---|---|
Delete nodes and edges | MATCH(p:Person{id:100}),(a:Account{id:1000}) DELETE(p)-[:Owns]->(a); |
DELETEPersonOwnAccount WHEREid=100ANDaccount_id=1000; |
Deleting nodes requires handling potential dangling edges. When DELETE CASCADE
is specified, DELETE
removes the associated edges of
nodes like DETACH DELETE
in openCypher. For more information, see Spanner
schema overview.
openCypher | Spanner Graph | |
---|---|---|
Delete nodes and associated edges | DETACHDELETE(:Account{id:1000}); |
DELETEAccount WHEREid=1000; |
Return mutation results
openCypher | Spanner Graph | |
---|---|---|
Return results after insertion or update | MATCH(p:Person{id:100}) SETp.country='United States' RETURNp.id,p.name; |
UPDATEPersonASp SETp.country='United States' WHEREp.id=100 THENRETURNid,name; |
Return results after deletion | DELETE(p:Person{id:100}) RETURNp.country; |
DELETEFROMPerson WHEREid=100 THENRETURNcountry; |