Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,9 @@ This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.htm
## [Development]
<!-- Do Not Erase This Section - Used for tracking unreleased changes -->

### Docs
- **GFQL**: Show Cypher string syntax above the fold in "10 Minutes to GFQL" and "Overview" pages so the first code a reader sees is familiar Cypher, not the native chain API.

## [0.53.7 - 2026-03-29]

### Fixed
Expand Down
75 changes: 49 additions & 26 deletions docs/source/gfql/about.rst
Original file line number Diff line number Diff line change
Expand Up @@ -75,37 +75,59 @@ GFQL is part of the open-source ``graphistry`` library. Install it using pip:

Ensure you have ``pandas`` or ``cudf`` installed, depending on whether you want to run on CPU or GPU.

Basic Concepts
--------------
Two Syntax Styles
------------------

GFQL supports two syntax styles through the same ``g.gfql(...)`` entrypoint:

**Cypher strings** — familiar if you know SQL or Cypher:

.. code-block:: python

# Filter nodes — returns a DataFrame
nodes_df = g.gfql("MATCH (n {type: 'person'}) RETURN n")._nodes

.. doc-test: skip

.. code-block:: python

# Extract a subgraph — returns a graph with ._nodes and ._edges
g2 = g.gfql("GRAPH { MATCH (a)-[e]->(b) WHERE e.interesting = true }")

**Native chain syntax** — composable Python objects:

.. code-block:: python

from graphistry import n, e_forward

Before we begin with examples, let's understand some basic concepts:
# Same node filter, chain form
nodes_df = g.gfql([ n({"type": "person"}) ])._nodes

- **Nodes and Edges:** In GFQL, graphs are represented using dataframes for nodes and edges.
- **Chaining:** GFQL queries are constructed by chaining operations that filter and traverse the graph.
- **Predicates:** Conditions applied to nodes or edges to filter them based on properties.
.. doc-test: skip

.. code-block:: python

# Same subgraph extraction, chain form
g2 = g.gfql([ e_forward({"interesting": True}) ])

Both styles run on the same vectorized engine, with the same CPU/GPU
acceleration. Use whichever you prefer — or mix them.

Examples
--------

1. Find Nodes of a Certain Type
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

You can filter nodes based on their properties using the ``n()`` function.
.. code-block:: python

**Example: Find all nodes of type "person"**

::
# Cypher style — returns a DataFrame of matching nodes
nodes_df = g.gfql("MATCH (n {type: 'person'}) RETURN n")._nodes

# Equivalent chain style
from graphistry import n

people_nodes_df = g.gfql([ n({"type": "person"}) ])._nodes
# people_nodes_df: DataFrame with 'a' and 'b' (the person nodes)

**Explanation:**

- ``n({"type": "person"})`` filters nodes where the ``type`` property is ``"person"``.
- ``g.gfql([...])`` applies the chain of operations to the graph ``g``.
- ``._nodes`` retrieves the resulting nodes dataframe.
nodes_df = g.gfql([ n({"type": "person"}) ])._nodes
# nodes_df: DataFrame with 'a' and 'b' (the person nodes)

.. graphviz::

Expand All @@ -129,17 +151,18 @@ You can filter nodes based on their properties using the ``n()`` function.
2. Find 2-Hop Edge Sequences with an Attribute
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Traverse multiple hops and filter edges based on attributes using ``e_forward()``.
Traverse multiple hops and filter edges based on attributes.

**Example: Find 2-hop paths where edges are marked as "interesting"**
.. code-block:: python

::
# Cypher style — GRAPH { } returns a subgraph with ._nodes and ._edges
g2 = g.gfql("GRAPH { MATCH (a)-[e]->(b) WHERE e.interesting = true }")

# Equivalent chain style
from graphistry import e_forward

g_2_hops = g.gfql([ e_forward({"interesting": True}, hops=2) ])
# g_2_hops._edges: edges a->b->c (both marked interesting)
g_2_hops.plot()
g2 = g.gfql([ e_forward({"interesting": True}, hops=2) ])
# g2._edges: edges a->b->c (both marked interesting)
g2.plot()

**Explanation:**

Expand Down
34 changes: 21 additions & 13 deletions docs/source/gfql/overview.rst
Original file line number Diff line number Diff line change
Expand Up @@ -52,8 +52,8 @@ Key GFQL Concepts
GFQL works on the same graphs as the rest of the PyGraphistry library. The operations run on top of the dataframe engine of your choice, with initial support for Pandas dataframes (CPU) and cuDF dataframes (GPU).

- **Nodes and Edges**: Represented using dataframes, making integration with Pandas and cuDF seamless
- **Functional**: Build queries by layering operations, similar to functional method chaining in Pandas
- **Query**: Run graph pattern matching using method `chain()` in a style similar to the popoular OpenCypher graph query language
- **Cypher strings**: Write queries as Cypher strings — ``g.gfql("MATCH (n) WHERE n.score > 5 RETURN n")``
- **Native chains**: Or compose queries as Python objects — ``g.gfql([n({"score": gt(5)})])``
- **Predicates**: Apply conditions to filter nodes and edges based on their properties, reusing the optimized native operations of the underlying dataframe engine
- **Same-path constraints (WHERE)**: Relate attributes across steps in a chain using `where`
- **Row pipelines (`MATCH ... RETURN` style)**: Move from graph pattern matches to tabular results with `rows()`, `where_rows()`, `return_()`, `order_by()`, `group_by()`, `skip()`, and `limit()`
Expand Down Expand Up @@ -85,27 +85,35 @@ If you need to enrich a graph and keep matching locally, use graph-preserving `c
Quick Examples
~~~~~~~~~~~~~~~

**Find Nodes of a Certain Type**
GFQL supports Cypher strings and native Python chains through the same ``g.gfql(...)`` entrypoint:

Example: Find all nodes where the `type` is `"person"`.
**Find Nodes of a Certain Type**

.. code-block:: python

from graphistry import n

people_nodes_df = g.gfql([ n({"type": "person"}) ])._nodes
print('Number of person nodes:', len(people_nodes_df))
# Cypher string — returns a DataFrame of matching nodes
nodes_df = g.gfql("MATCH (n {type: 'person'}) RETURN n")._nodes

**Visualize 2-Hop Edge Sequences with an Attribute**
# Equivalent native chain
from graphistry import n
nodes_df = g.gfql([ n({"type": "person"}) ])._nodes

Example: Find 2-hop paths where edges have `"interesting": True`.
**Extract a Subgraph**

.. code-block:: python

from graphistry import n, e_forward
# Cypher string — GRAPH { } returns a subgraph with ._nodes and ._edges
g2 = g.gfql(
"GRAPH { "
"MATCH (a)-[e]->(b) "
"WHERE e.interesting = true "
"}"
)

g_2_hops = g.gfql([n(), e_forward({"interesting": True}, hops=2) ])
g_2_hops.plot()
# Equivalent native chain
from graphistry import n, e_forward
g2 = g.gfql([n(), e_forward({"interesting": True}, hops=2) ])
g2.plot()

**Same-Path Constraints (WHERE)**

Expand Down
Loading