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 ...") or g.gfql("...", language="cypher") for Cypher syntax on the current bound Plottable.

  • 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("...") or g.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 WHERE inside GRAPH { } to reduce the graph passed to the next stage while staying graph-shaped in _nodes and _edges. Today this path is strict: GFQL supports filters it can apply to one node or one edge table without building joined rows, such as seed.degree >= 10, reach.weight > 5, seed.score > 0.25 OR seed.score IS NULL, and searchAny(seed, 'alice').

Predicates that require joined match rows, such as WHERE (a)-[:R]->(), EXISTS { ... }, or conditions spanning multiple aliases, are rejected for now instead of triggering hidden materialization. Future support should make that eager boundary explicit, for example through an inspectable plan or warning mode, and then project the rows back to graph state.

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:

  • MATCH and WHERE clauses inside GRAPH { }

  • Graph-preserving CALL graphistry.*.write() inside GRAPH { }

  • GRAPH g = GRAPH { } named bindings with lexical scoping

  • USE g to 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:

  • MATCH and a bounded OPTIONAL MATCH subset

  • WHERE

  • RETURN and WITH

  • ORDER BY, SKIP, LIMIT, and DISTINCT

  • UNWIND

  • supported UNION / UNION ALL and CALL graphistry.* flows when executed directly through g.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

MATCH / WHERE / RETURN / WITH / ORDER BY / SKIP / LIMIT / DISTINCT

Supported

Core read-only Cypher-in-GFQL path.

GRAPH { MATCH ... } / GRAPH g = ... / USE g

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.

OPTIONAL MATCH

Partial

Supported for a bounded Cypher-in-GFQL subset, not the full Cypher null-extension surface.

UNWIND

Partial

Supported at top level, after MATCH, in row-only pipelines, and in the narrow graph-backed MATCH ... WITH collect([DISTINCT] alias) AS list UNWIND list AS alias MATCH ... RETURN continuation shape, but not in arbitrary graph/row interleavings.

UNION / UNION ALL and CALL graphistry.*

Partial

Execute directly through g.gfql("..."). Helper translation to a single Chain is stricter.

Variable-length relationship patterns

Partial

Direct Cypher supports endpoint traversals such as [*2], [*1..3], [*], and typed forms like [:R*2..4]; connected multi-relationship variable-length patterns; and bounded/exact/fixed-point variable-length WHERE pattern predicates in the current row-shaped subset. Path/list-carrier uses and unsupported path/row-shaping cases still fail fast.

CREATE / DELETE / SET

Not supported

GFQL’s Cypher surface is read-only.

Multiple disconnected MATCH patterns and arbitrary joins

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 MATCH queries with node aliases, relationship aliases, inline property maps, and top-level params=... 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 MATCH clauses 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 NULL and IS NOT NULL predicates.

  • String predicates STARTS WITH, ENDS WITH, and CONTAINS.

  • Regex match =~ (openCypher/neo4j-standard), e.g. WHERE n.name =~ '(?i)al.*'. Uses a full-string / anchored match (like neo4j’s Java-regex =~), so n.name =~ 'AB' matches only 'AB' — use .* / ^..$ for partial matches. Inline flags such as (?i) (case-insensitive), (?m), and (?s) are honored. Composes through AND / OR / NOT. Engine caveat: on engine='cudf', (?m) / (?s), lookaround, backreferences, and (?i) combined with uppercase escape classes (e.g. (?i)\\D+; lowercase \\d/\\. work), case-crossing character ranges ((?i)[A-z]), hex escapes, and non-ASCII patterns raise NotImplementedError (libcudf regex limits — declined honestly rather than approximated); use engine='pandas' for those patterns. (LIKE / ILIKE are not part of Cypher or GQL — use =~, CONTAINS, or STARTS WITH instead.)

  • 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 as WHERE (n)-[*]-() and WHERE (n)-[:R*2]->().

  • EXISTS { <pattern> } pattern-existence subqueries (openCypher-standard) in WHERE position, e.g. WHERE EXISTS { (n)-[:R]->() } and WHERE NOT EXISTS { (n)--() } — the declarative prune-isolated building blocks. Aliases introduced inside the braces are existentially scoped (EXISTS { (n)--(m) } is fine even when m is unbound outside), inline property maps work (EXISTS { (n)-[:R {w: 1}]->() }), and the one supported inner WHERE form is endpoint inequality: EXISTS { (n)--(m) WHERE m <> n } — “has a neighbor other than itself”, i.e. the drop-self-loop prune-isolated flavor. Runs natively on all four engines. Not yet supported (clear errors): EXISTS in RETURN/WITH projections, general inner WHERE clauses, multi-pattern bodies, full MATCH .. RETURN subquery bodies, and EXISTS inside GRAPH { } pipelines. For prune-isolated in GRAPH STATE (nodes AND edges back), use edge patterns instead: GRAPH { MATCH (a)-[e]-(b) } keeps every edge-touching node with ALL its edges (self-loops included); add WHERE a.id <> b.id for the drop-self-loop variant.

  • Pattern predicates can be combined with row predicates in the current boolean subset, including AND / OR / XOR and NOT forms.

Scalar Functions and Operators#

Standard openCypher/neo4j scalar functions and operators usable in WHERE and RETURN expressions:

  • Arithmetic + - * / %. Chained comparisons such as WHERE 1 < n.age < 65 are supported. (The ^ exponentiation operator is not yet available.)

  • Numeric functions abs, sqrt, sign, floor, ceil (alias ceiling, per Cypher 25 / GQL), and round(x) / round(x, precision) (returns a float). round follows neo4j’s tie-breaking: precision 0 rounds ties toward positive infinity (round(-1.5)-1.0, round(2.5)3.0); precision > 0 rounds ties away from zero (round(-1.55, 1)-1.6). One documented deviation at precision > 0: neo4j rounds via the number’s decimal string (Java BigDecimal.valueOf), so a value like 2.675 — stored as the binary double 2.67499… — gives 2.68 in neo4j but 2.67 here (both engines, consistently binary-double). Precision above 308 is the identity (a float64 has no digits there).

  • String helpers toLower / toUpper and their GQL-conformance aliases lower / upper (the idiomatic case-insensitive compare, e.g. WHERE toLower(n.name) = 'bob'), plus substring and size, and conversions toInteger / toFloat / toString / toBoolean and coalesce.

  • Regex =~ (see WHERE Forms above).

  • searchAny(entity, term[, opts]) — cross-column search predicate (WHERE position; GFQL extension for the viz filter pipeline): True where ANY of the entity’s columns matches term. Inspector semantics: OR across columns, case-insensitive substring by default, regex opt-in; dtype-gated — string columns always, integer columns iff the term is a numeric literal (/^[0-9.-]+$/); floats/dates/booleans only via the explicit list. Options map: {caseSensitive: true, regex: true, columns: ['name', ...]} (unknown keys error, listing the valid ones). Composes with other WHERE predicates through AND/OR/NOT; nodes and edges independently searchable with different terms. Runs natively on all four engines for node aliases; an edge-alias searchAny(r, ...) declines honestly on polars pending multi-entity binding-row support (use engine='pandas'), and explicit non-string columns beyond ints/bools likewise decline on polars and cuDF rather than risk divergent stringification (float repr differs across engines). The regex path obeys the same per-engine decline rules as =~. Python twins: ComputeMixin.search_nodes() / ComputeMixin.search_edges().

LIKE / ILIKE and BETWEEN are intentionally not provided — they are not part of Cypher or GQL; use =~ / CONTAINS / STARTS WITH and a <= x AND x <= b (or chained a <= x <= b) respectively.

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 b

  • MATCH (a)-[:R*1..3]->(b) RETURN b

  • MATCH (a)<-[*2]-(b) RETURN b

  • MATCH (a)-[:R*1..2]-(b) RETURN b

  • MATCH (a)-[:R*2]->(b)-[:S]->(c) RETURN c

  • MATCH (a)-[:R]->(b), (b)-[:S*1..2]->(c) RETURN a.id AS a_id, c.id AS c_id

  • MATCH (n) WHERE (n)-[:R*2]->() RETURN n

  • MATCH (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 r or count(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.prop when it would require unsupported row shaping

  • multi-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 / WITH projections with aliases, RETURN *, DISTINCT, ORDER BY, SKIP, and LIMIT.

  • Terminal WITH queries and multiple WITH stages.

  • WITH ... WHERE row filtering.

  • Aggregation/grouping via Cypher projection semantics, including count, count(DISTINCT ...), collect, collect(DISTINCT ...), sum, max, and size(...).

  • 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 ... RETURN re-entry shape, including connected suffix projections in the current supported row-binding subset.

Whole-Entity RETURN Output Shape#

A terminal RETURN of a whole node or relationship (RETURN a rather than RETURN a.prop) emits structured flattened columns, one per field, named <alias>.<field>:

g.gfql("MATCH (a:Person) RETURN a")
# result._nodes columns: a.id, a.name, a.age, ...  (one column per field)

This is directly usable (no string to re-parse) and survives JSON / CSV / Parquet / Arrow serialization and plot(). To recover the human-readable Cypher display string ((:Person {name: 'Alice'})) on demand, use the presentation helper:

from graphistry.compute.gfql.cypher.result_postprocess import render_entity_text
text_series = render_entity_text(result, "a")            # nodes
text_series = render_entity_text(result, "r", table="edges")  # relationships

Notes:

  • An aliased property projection of the same field (RETURN a, a.val) is de-duplicated — you get a single a.val column, not two.

  • A whole entity with no fields to flatten (no id binding, no properties, no type/label — in practice only an edge whose graph has no edge-id binding) has nothing to flatten and falls back to a single Cypher-display-text column under the bare alias. Nodes always carry an id field and always flatten.

Procedure And Multi-Branch Forms#

  • Direct execution of UNION row queries through g.gfql("...").

  • Direct execution of UNION ALL row queries through g.gfql("...").

  • Direct execution of row-returning CALL graphistry.* procedures, including:

    • CALL graphistry.degree()

    • CALL graphistry.degree YIELD nodeId RETURN nodeId

    • CALL graphistry.igraph.pagerank() YIELD nodeId, pagerank RETURN nodeId

    • CALL 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 omit YIELD ... RETURN .... For example, CALL graphistry.degree() projects its default outputs into _nodes and leaves an empty placeholder _edges frame (for example, assert result._edges.empty); use .write() when you want enrich-then-MATCH graph workflows with traversable edges (for example, assert not result._edges.empty).

  • For graphistry.igraph.<alg>() and node-oriented graphistry.cugraph.<alg>(), row mode uses nodeId plus the algorithm output columns (for example, pagerank or louvain). For edge-oriented graphistry.cugraph.<alg>(), row mode uses source / destination plus the edge result columns. Topology-returning procedures such as graphistry.cugraph.k_core() or graphistry.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 use source / destination + the algorithm column, and topology-returning calls such as k_core require .write(). Multi-output hits returns nodeId, hubs, and authorities.

    The same curated NetworkX algorithm subset is available from regular Python as g.compute_networkx(...) for users who do not need the local Cypher CALL path.

  • Local Cypher CALL options accept one optional map argument. The top-level keys mirror compute_igraph() / compute_cugraph() options such as out_col, directed, kind, use_vids, and params; any extra keys are forwarded into the nested algorithm params dictionary.

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 networkx subset, graphistry.nx.* is not part of the current local Cypher CALL surface.

  • cypher_to_gfql() stays stricter than direct execution and intentionally rejects UNION / UNION ALL and row-returning CALL flows because they are not representable as a single GFQL Chain.

Expression Families#

  • Arithmetic, boolean, comparison, and null-propagation expressions.

  • CASE expressions.

  • Graph introspection helpers such as labels(), type(), keys(), and properties().

  • Dynamic graph property lookup such as n['name'] and n[$idx].

  • List predicates such as all(...), any(...), none(...), and single(...).

  • Temporal constructors and operations over date, time, datetime, localtime, localdatetime, and duration in the current vectorized subset.

Bounded / Partial Forms#

  • OPTIONAL MATCH works for a bounded subset, including top-level and bound optional rows, but not the full Cypher null-extension surface.

  • UNWIND works at top level, after MATCH, in row-only pipelines, and in the narrow graph-backed MATCH ... WITH collect([DISTINCT] alias) AS list UNWIND list AS alias MATCH ... RETURN continuation shape, but not in arbitrary graph/row interleavings.

  • MATCH ... WITH ... MATCH ... RETURN is 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 r or count(r).

  • Connected multihop shapes that still require unsupported path/relationship-carrier row shaping.

  • Multiple disconnected MATCH patterns used as arbitrary joins.

  • Multi-pattern re-entry shapes beyond the bounded single MATCH ... WITH ... MATCH ... RETURN form.

  • 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 raises GFQLValidationError.

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 uses strict=False by 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 GFQL Chain. It is intentionally stricter than direct execution through g.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 keep validate=True (default) for local preflight before upload.

  • Need remote database Cypher against Neo4j/Bolt-style backends instead of remote GFQL? Use graphistry.cypher("...") or g.cypher("...").

  • Need a pure GFQL chain object? Use cypher_to_gfql() when the query fits a single Chain.

  • 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) or e_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.