Cypher Syntax In GFQL#
PyGraphistry supports a read-only Cypher surface directly through GFQL on a
bound graph. This is the on-ramp for Cypher users who want familiar
declarative syntax and graph-pattern semantics, but executed by GFQL’s fully
vectorized columnar engine and open-source GPU runtime instead of a
database-only runtime. Start here when you want to execute a Cypher query
through g.gfql("MATCH ...") instead of translating it into native GFQL
operators by hand.
Choose The Right Cypher Entrypoint#
Use
g.gfql("MATCH ...")org.gfql("...", language="cypher")for Cypher syntax on the current boundPlottable.Use
g.gfql_remote([...])for remote GFQL execution when the dataset size or hardware profile calls for running GFQL on remote infrastructure.Use
graphistry.cypher("...")org.cypher("...")for remote database Cypher over Bolt/Neo4j-style integrations. That is a separate execution path.
Quickstart#
Assume g is a bound graph with nodes and edges already attached.
top_people = g.gfql(
"MATCH (p:Person) "
"RETURN p.name AS name "
"ORDER BY name DESC "
"LIMIT 5"
)
top_people._nodes
String queries default to language="cypher", so the explicit selector is
usually optional:
same_result = g.gfql(
"MATCH (p:Person) RETURN p.name AS name ORDER BY name DESC LIMIT 5",
language="cypher",
)
Parameters#
Use params=... instead of manual string interpolation:
limited = g.gfql(
"MATCH (p:Person) "
"RETURN p.name AS name "
"ORDER BY name DESC "
"LIMIT $top_n",
params={"top_n": 2},
)
limited._nodes
Graph Constructors (GRAPH { })#
Note
GRAPH { } is a GFQL extension — not part of openCypher, and GQL’s
first edition (ISO/IEC 39075:2024) deferred graph constructors to a future
revision. Standard Cypher and GQL both force query results through
row/path-centric serialization. GRAPH { } closes that gap by keeping
results in graph state (both _nodes and _edges), enabling
composable graph-pipeline workflows.
Use GRAPH { MATCH ... } when you want the matched subgraph back in graph
state instead of a row table:
subgraph = g.gfql(
"GRAPH { "
" MATCH (seed)-[reach]-(nbr) "
" WHERE seed.degree >= $degree_cutoff "
"}",
params={"degree_cutoff": 10},
)
subgraph._nodes
subgraph._edges
Use GRAPH g = GRAPH { ... } to bind a named graph, then USE g to
query it:
result = g.gfql(
"GRAPH g1 = GRAPH { "
" MATCH (seed)-[reach]-(nbr) "
" WHERE seed.degree >= $degree_cutoff "
"} "
"USE g1 "
"MATCH (n) "
"RETURN n.id AS id, n.degree AS degree "
"ORDER BY degree DESC LIMIT 10",
params={"degree_cutoff": 10},
)
Multi-stage graph pipelines chain constructors:
g1 = g.gfql(
"GRAPH { "
" MATCH (seed)-[reach]-(nbr) "
" WHERE seed.degree >= $degree_cutoff "
"}",
params={"degree_cutoff": 10},
)
g2 = g1.gfql("CALL graphistry.cugraph.pagerank.write()", engine="cudf")
g3 = g2.gfql(
"GRAPH { "
" MATCH (core)-[halo]-(nbr) "
" WHERE core.pagerank >= $pagerank_cutoff "
"}",
params={"pagerank_cutoff": 0.25},
)
The graph constructor surface supports:
MATCHandWHEREclauses insideGRAPH { }Graph-preserving
CALL graphistry.*.write()insideGRAPH { }GRAPH g = GRAPH { }named bindings with lexical scopingUSE gto switch the current graph (works both inside constructors and in the outer query)Variable scoping: pattern variables inside
GRAPH { }do not leak
This enables single-expression pipelines that filter, enrich, and query:
result = g.gfql(
"GRAPH g1 = GRAPH { MATCH (a)-[r]->(b) WHERE a.score > 10 } "
"GRAPH g2 = GRAPH { USE g1 CALL graphistry.degree.write() } "
"USE g2 "
"MATCH (n) RETURN n.id AS id, n.degree AS degree "
"ORDER BY degree DESC LIMIT 10"
)
Inside GRAPH { }, only MATCH, WHERE, USE, and graph-preserving
CALL graphistry.*.write() are allowed. Row-oriented clauses (RETURN,
ORDER BY, SKIP, LIMIT, DISTINCT, UNWIND, WITH) and
row-returning CALL (without .write()) are not allowed inside the
constructor — use them in the outer query after USE.
Supported Cypher Surface Through g.gfql()#
The current GFQL Cypher compiler intentionally supports a bounded read-only surface. At a high level, that includes:
MATCHand a boundedOPTIONAL MATCHsubsetWHERERETURNandWITHORDER BY,SKIP,LIMIT, andDISTINCTUNWINDsupported
UNION/UNION ALLandCALL graphistry.*flows when executed directly throughg.gfql("...")
For exact RETURN / WITH row semantics after pattern matching, see
GFQL RETURN (Row Pipelines). For same-path WHERE comparisons, see GFQL WHERE (Same-Path Constraints).
Support Matrix#
Query shape |
Status |
Notes |
|---|---|---|
|
Supported |
Core read-only Cypher-in-GFQL path. |
|
Partial |
GFQL extension (not in openCypher; GQL deferred graph constructors). Returns matched subgraph in graph state. Supports named bindings and scoped graph switching via USE. |
|
Partial |
Supported for a bounded Cypher-in-GFQL subset, not the full Cypher null-extension surface. |
|
Partial |
Supported at top level, after |
|
Partial |
Execute directly through |
Variable-length relationship patterns |
Partial |
Direct Cypher supports endpoint traversals such as |
|
Not supported |
GFQL’s Cypher surface is read-only. |
Multiple disconnected |
Not supported |
Split the work into separate GFQL / dataframe steps. |
Full Cypher expression and function surface in row expressions |
Partial |
The current row-expression subset is intentionally smaller than full Cypher; finish advanced logic in pandas/cuDF when needed. |
Supported Syntax Forms#
The matrix above is clause-level. This section lists the main user-visible syntax forms on the current Cypher-in-GFQL surface.
Pattern Matching Forms#
Single-pattern
MATCHqueries with node aliases, relationship aliases, inline property maps, and top-levelparams=...binding.Node labels and multi-label node patterns such as
(p:Person:Admin).Relationship direction forms
->,<-, and undirected-[]-.Relationship type alternation such as
[r:KNOWS|HATES].Single variable-length relationship patterns, including
[*n],[*m..n],[*], and typed forms such as[:R*2..4].Connected patterns that mix variable-length and fixed-length relationships, such as
MATCH (a)-[:R*2]->()-[:S]->(c) RETURN c.Connected comma-separated patterns such as
MATCH (a)-[:A]->(b), (b)-[:B]->(c).Repeated
MATCHclauses when they stay connected through shared aliases.Path variable binding such as
MATCH p = (n)-[r]->(b)when the path variable itself is not the projected output.
WHERE Forms#
Literal and parameter comparisons on node and edge properties.
Same-path alias comparisons such as
WHERE p.team = q.team.IS NULLandIS NOT NULLpredicates.String predicates
STARTS WITH,ENDS WITH, andCONTAINS.Label predicates such as
WHERE b:Foo:Bar.Relationship-type predicates such as
WHERE type(r) = 'KNOWS'.Positive relationship-existence pattern predicates such as
WHERE (n)-[:R]->()and variable-length existence checks such asWHERE (n)-[*]-()andWHERE (n)-[:R*2]->().Pattern predicates can be combined with row predicates in the current boolean subset, including
AND/OR/XORandNOTforms.
Variable-Length Relationship Boundary#
Direct Cypher multihop support remains intentionally bounded. The supported
direct forms include endpoint traversals, connected multi-relationship
patterns, and variable-length WHERE pattern predicates where the result
stays in the current row-shaping subset, for example:
MATCH (a)-[*2]->(b) RETURN bMATCH (a)-[:R*1..3]->(b) RETURN bMATCH (a)<-[*2]-(b) RETURN bMATCH (a)-[:R*1..2]-(b) RETURN bMATCH (a)-[:R*2]->(b)-[:S]->(c) RETURN cMATCH (a)-[:R]->(b), (b)-[:S*1..2]->(c) RETURN a.id AS a_id, c.id AS c_idMATCH (n) WHERE (n)-[:R*2]->() RETURN nMATCH (n) WHERE NOT (n)-[:R*2]->() RETURN n.id AS id
The current compiler explicitly rejects these remaining subfamilies with
GFQLValidationError instead of attempting unsound execution:
path/list-carrier use of a variable-length relationship alias, such as
RETURN rorcount(r)shapes that still require unsupported path/relationship-carrier row shaping around a variable-length segment
connected multi-pattern relationship-alias projection such as
RETURN r/r.propwhen it would require unsupported row shapingmulti-alias
RETURN *projections that would require unsupported path/multi-source row shaping
Row And Row-Pipeline Forms#
Top-level row-only queries such as
RETURN 1 AS x.RETURN/WITHprojections with aliases,RETURN *,DISTINCT,ORDER BY,SKIP, andLIMIT.Terminal
WITHqueries and multipleWITHstages.WITH ... WHERErow filtering.Aggregation/grouping via Cypher projection semantics, including
count,count(DISTINCT ...),collect,collect(DISTINCT ...),sum,max, andsize(...).Top-level
UNWIND ... RETURN ...queries.Mixed graph/row queries such as
MATCH ... UNWIND ... RETURN ....Connected multi-alias scalar projection such as
MATCH (a)-[:R]->(b), (b)-[:S]->(c) RETURN a.id AS a_id, c.id AS c_id.The bounded
MATCH ... WITH ... MATCH ... RETURNre-entry shape, including connected suffix projections in the current supported row-binding subset.
Procedure And Multi-Branch Forms#
Direct execution of
UNIONrow queries throughg.gfql("...").Direct execution of
UNION ALLrow queries throughg.gfql("...").Direct execution of row-returning
CALL graphistry.*procedures, including:CALL graphistry.degree()CALL graphistry.degree YIELD nodeId RETURN nodeIdCALL graphistry.igraph.pagerank() YIELD nodeId, pagerank RETURN nodeIdCALL graphistry.cugraph.louvain()CALL graphistry.cugraph.edge_betweenness_centrality()
Direct execution of standalone graph-preserving
CALL graphistry.*.write()procedures, including:CALL graphistry.degree.write()CALL graphistry.igraph.pagerank.write()CALL graphistry.cugraph.edge_betweenness_centrality.write()CALL graphistry.cugraph.k_core.write()CALL graphistry.igraph.spanning_tree.write()CALL graphistry.nx.edge_betweenness_centrality.write()CALL graphistry.nx.k_core.write()CALL graphistry.nx.pagerank.write()
Bare procedures without
.write()stay row-returning even when you omitYIELD ... RETURN .... For example,CALL graphistry.degree()projects its default outputs into_nodesand leaves an empty placeholder_edgesframe (for example,assert result._edges.empty); use.write()when you want enrich-then-MATCHgraph workflows with traversable edges (for example,assert not result._edges.empty).For
graphistry.igraph.<alg>()and node-orientedgraphistry.cugraph.<alg>(), row mode usesnodeIdplus the algorithm output columns (for example,pagerankorlouvain). For edge-orientedgraphistry.cugraph.<alg>(), row mode usessource/destinationplus the edge result columns. Topology-returning procedures such asgraphistry.cugraph.k_core()orgraphistry.igraph.spanning_tree()require.write().graphistry.nx.*remains a curated CPU subset rather than the full NetworkX API, but it includes common node, edge, multi-output, and graph-returning forms:graphistry.nx.pagerank()/.write()graphistry.nx.betweenness_centrality()/.write()graphistry.nx.degree_centrality()/.write()graphistry.nx.closeness_centrality()/.write()graphistry.nx.eigenvector_centrality()/.write()graphistry.nx.katz_centrality()/.write()graphistry.nx.connected_components()/.write()graphistry.nx.strongly_connected_components()/.write()graphistry.nx.core_number()/.write()graphistry.nx.hits()/.write()graphistry.nx.edge_betweenness_centrality()/.write()graphistry.nx.k_core.write()
Node calls use
nodeId+ the algorithm column, edge calls usesource/destination+ the algorithm column, and topology-returning calls such ask_corerequire.write(). Multi-outputhitsreturnsnodeId,hubs, andauthorities.This NetworkX algorithm subset is GFQL local Cypher only. The regular NetworkX plugin API remains conversion-focused (for example,
from_networkx()/networkx2pandas()) and does not currently expose a publiccompute_networkx()method.Local Cypher
CALLoptions accept one optional map argument. The top-level keys mirrorcompute_igraph()/compute_cugraph()options such asout_col,directed,kind,use_vids, andparams; any extra keys are forwarded into the nested algorithmparamsdictionary.
Component-labeling examples:
# Graph-enrichment mode (keeps traversable _edges)
g.gfql(
"CALL graphistry.cugraph.connected_components.write({out_col: 'wcc_id', directed: false})",
language="cypher",
)
g.gfql(
"CALL graphistry.cugraph.strongly_connected_components.write({out_col: 'scc_id', directed: true})",
language="cypher",
)
# Row mode (no .write): returns nodeId + output column rows
g.gfql(
"CALL graphistry.cugraph.connected_components({out_col: 'wcc_row', directed: false})",
language="cypher",
)
g.gfql(
"CALL graphistry.nx.connected_components({directed: false})",
language="cypher",
)
Outside that curated
networkxsubset,graphistry.nx.*is not part of the current local CypherCALLsurface.cypher_to_gfql()stays stricter than direct execution and intentionally rejectsUNION/UNION ALLand row-returningCALLflows because they are not representable as a single GFQLChain.
Expression Families#
Arithmetic, boolean, comparison, and null-propagation expressions.
CASEexpressions.Graph introspection helpers such as
labels(),type(),keys(), andproperties().Dynamic graph property lookup such as
n['name']andn[$idx].List predicates such as
all(...),any(...),none(...), andsingle(...).Temporal constructors and operations over
date,time,datetime,localtime,localdatetime, anddurationin the current vectorized subset.
Bounded / Partial Forms#
OPTIONAL MATCHworks for a bounded subset, including top-level and bound optional rows, but not the full Cypher null-extension surface.UNWINDworks at top level, afterMATCH, in row-only pipelines, and in the narrow graph-backedMATCH ... WITH collect([DISTINCT] alias) AS list UNWIND list AS alias MATCH ... RETURNcontinuation shape, but not in arbitrary graph/row interleavings.MATCH ... WITH ... MATCH ... RETURNis limited to the bounded single re-entry shape. Connected suffix projections with whole-row and carried scalar bindings are supported in the current subset, but this still does not generalize to arbitrary re-entry plans.
Not Supported Today#
Variable-length relationship aliases used as path/list carriers, such as
RETURN rorcount(r).Connected multihop shapes that still require unsupported path/relationship-carrier row shaping.
Multiple disconnected
MATCHpatterns used as arbitrary joins.Multi-pattern re-entry shapes beyond the bounded single
MATCH ... WITH ... MATCH ... RETURNform.RETURN *after unsupported re-entry shapes or when it would require unsupported multi-alias/path projection shaping.CREATE,DELETE,SET, and other write clauses.Generic database procedures outside
CALL graphistry.*.The full Cypher expression/function surface.
Validation And Unsupported Shapes#
Unsupported but syntactically valid query shapes on this Cypher surface raise
GFQLValidationError, usually before execution starts.Invalid Cypher syntax raises
GFQLSyntaxError.Passing a string query with an unsupported
language=...selector also raisesGFQLValidationError.
That fail-fast behavior is intentional: the current GFQL Cypher compiler prefers explicit validation over silently returning wrong rows.
Static Validation / Preflight Check#
If you want to know whether a query fits the current Cypher-in-GFQL subset before execution, start with the bound-graph inline preflight APIs:
g.gfql_validate(
"MATCH (p) RETURN p.name AS name ORDER BY name DESC LIMIT $top_n",
params={"top_n": 5},
# strict=True is the default for local bound-graph preflight
)
# On failure:
# - GFQLSyntaxError for invalid syntax
# - GFQLValidationError for unsupported/scheme-invalid shapes
Use
g.gfql_validate(...)when you want a stable validate-only entrypoint that never executes query operators and raises structured exceptions on invalid queries.Use
g.gfql(..., validate=True)when you want execution guarded by a local preflight check. For Cypher strings, this uses schema-aware strict preflight by default.Use
g.gfql_remote(..., validate=True)when you want remote execution guarded by local preflight before upload/network dispatch. For Cypher strings, remote preflight usesstrict=Falseby default because remote schema is authoritative.Use
parse_cypher()when you only want grammar validation and access to the parsed representation.Use
compile_cypher()when you need low-level compiler/lowering output for tooling or whitebox inspection.Use
cypher_to_gfql()only when you specifically need a single GFQLChain. It is intentionally stricter than direct execution throughg.gfql("...").
Low-level helper example:
from graphistry.compute.exceptions import GFQLSyntaxError, GFQLValidationError
from graphistry.compute.gfql.cypher import parse_cypher, compile_cypher
query = "MATCH (p:Person) RETURN p.name AS name"
try:
parsed = parse_cypher(query) # grammar + AST checks
compiled = compile_cypher(query) # compiler/lowering checks
except GFQLSyntaxError as exc:
print("Invalid Cypher syntax for g.gfql(\"MATCH ...\"):", exc)
except GFQLValidationError as exc:
print("Valid Cypher, but outside the current GFQL Cypher surface:", exc)
Common Rewrites#
Need remote execution on Graphistry infrastructure instead of running against the current bound graph? Prefer
g.gfql_remote(...)for remote GFQL, and keepvalidate=True(default) for local preflight before upload.Need remote database Cypher against Neo4j/Bolt-style backends instead of remote GFQL? Use
graphistry.cypher("...")org.cypher("...").Need a pure GFQL chain object? Use
cypher_to_gfql()when the query fits a singleChain.Need fixed-length, bounded, or fixed-point endpoint traversal? Direct Cypher already supports
[*2],[*1..3], and[*]for that endpoint-only slice.Need aliasable intermediate hops, output slicing, or mixed connected-pattern multihop control? Rewrite in native GFQL with explicit hop bounds such as
e_forward(min_hops=1, max_hops=3)ore_forward(to_fixed_point=True), or unroll the traversal into explicit chain steps.Need write semantics or arbitrary joins? Keep Cypher syntax for the supported read-only part and finish the rest in a database or in pandas/cuDF.
Compiler Helper APIs#
Use the helper APIs when you want to inspect or reuse compiler output rather than run the query immediately:
from graphistry.compute.gfql.cypher import (
parse_cypher,
compile_cypher,
cypher_to_gfql,
gfql_from_cypher,
)
parsed = parse_cypher("MATCH (p:Person) RETURN p.name AS name")
compiled = compile_cypher("MATCH (p:Person) RETURN p.name AS name")
chain = cypher_to_gfql("MATCH (p:Person) RETURN p.name AS name")
cypher_to_gfql() / gfql_from_cypher() are intentionally limited to
queries that can be represented as a single GFQL Chain. If a query requires
UNION or a row-returning CALL flow, execute it directly through
g.gfql("...", language="cypher") instead.
See GFQL Cypher Syntax API Reference for the helper reference.
Translation Vs Direct Execution#
This page is about direct Cypher-syntax execution through
g.gfql("MATCH ...") on a bound graph.
If you want to run the query now, use
g.gfql("MATCH ...").If you want to understand how Cypher maps into GFQL operators and wire protocol, use Cypher to GFQL Python & Wire Protocol Mapping.
If you want native GFQL chain syntax instead of strings, start with GFQL Quick Reference.