ArcFlow
Company
Managed Services
Markets
  • News
  • LOG IN
  • GET STARTED

OZ brings Visual Intelligence to physical venues, a managed edge layer that lets real-world environments see, understand, and act in real time.

Talk to us

ArcFlow

  • World Models
  • Sensors

Managed Services

  • OZ VI Venue 1
  • Case Studies

Markets

  • Sports
  • Broadcasting
  • Robotics

Company

  • About
  • Technology
  • Careers
  • Contact

Ready to see it live?

Talk to the OZ team about deploying at your venues, from a single pilot match to a full regional rollout.

Schedule a deployment review

© 2026 OZ. All rights reserved.

LinkedIn
ArcFlow Docs
Get Started
  • Get Started
  • Quickstart
  • Installation
  • Project Setup
  • Platforms
  • Bindings
  • Licensing
  • Pricing
Capabilities
  • Vector Search
  • Graph Algorithms
  • Sync
  • MCP Server (AI Agents)
  • Live Queries
  • Programs
  • Temporal
  • Spatial
  • Trusted RAG
  • Behavior Graph
  • Agent-Native
  • Event Sourcing
  • GPU Acceleration
  • Intent Relay
Concepts
  • World Model
  • Graph Model
  • Query Language (GQL)
  • Graph Patterns
  • SQL vs GQL
  • Parameters
  • Query Results
  • Persistence & WAL
  • Error Handling
  • Observations & Evidence
  • Confidence & Provenance
  • Proof Artifacts & Gates
  • Skills
GQL / WorldCypher
  • Overview
  • MATCH
  • WHERE
  • RETURN
  • OPTIONAL MATCH
  • CREATE
  • SET
  • MERGE
  • DELETE
  • REMOVE
  • WITH
  • UNION
  • UNWIND
  • CASE
  • Spatial Queries
  • Temporal Queries
  • Algorithms Reference
  • Triggers
Schema
  • Overview
  • Indexes
  • Constraints
  • Data Types
Functions
  • Built-in Functions
  • Aggregations
  • Procedures
  • Shortest Path
  • EXPLAIN
  • PROFILE
Skills
  • Overview
  • CREATE SKILL
  • PROCESS NODE
  • REPROCESS EDGES
Operations
  • CLI
  • REPL Commands
  • Snapshot & Restore
  • Server Modes & PG Wire
  • Persistence
  • Import & Export
  • Docker
  • Architecture
  • Cloud Architecture
  • Sync Protocol (Deep Dive)
Guides
  • Agent Integration
  • World Model
  • Graph Model Fundamentals
  • Trusted RAG
  • Using Skills
  • Behavior Graphs
  • Swarm & Multi-Agent
  • Migration Guide
  • Filesystem Workspace
  • From SQL to GQL
  • ArcFlow for Coding Agents
  • Data Quality & Pipeline Integrity
  • Code Intelligence
Tutorials
  • Knowledge Graph
  • Entity Linking
  • Vector Search
  • Graph Algorithms
Recipes
  • CRUD
  • Multi-MATCH
  • MERGE (Upsert)
  • Full-Text Search
  • Temporal Queries
  • Batch Projection
  • GraphRAG
Use Cases
  • Agent Tooling
  • Knowledge Management
  • RAG Pipeline
  • Fraud Detection
  • Sports Analytics
  • Grounded Neural Objects
  • Behavior Graphs
  • Autonomous Systems
  • Digital Twins
  • Robotics & Perception
Reference
  • TypeScript API
  • GQL Conformance
  • Compatibility Matrix
  • Glossary
  • Data Types
  • Operators
  • Error Codes
  • Known Issues

Graph Patterns

In SQL you describe conditions on rows. In GQL you describe shapes in the graph — and the engine finds everything that matches that shape.

This is the shift. It changes not just the syntax but how you think about the problem.

What a pattern is#

A pattern is a template for a subgraph. It specifies nodes, the relationships between them, and any constraints on their properties. The engine scans the graph and returns every subgraph that fits the template.

-- "Find every Person connected to a Company by a WORKS_AT relationship"
MATCH (p:Person)-[:WORKS_AT]->(c:Company)
RETURN p.name, c.name

The MATCH clause holds the pattern. Everything inside it — (p:Person), -[:WORKS_AT]->, (c:Company) — describes a shape, not a filter condition.

Node patterns#

A node pattern describes a single node:

(variable:Label {property: value})
ElementMeaning
(n)Any node, bound to variable n
(n:Person)Any node labeled :Person
(n:Person {name: 'Alice'})A Person node where name equals 'Alice'
(:Person)A Person node (anonymous — no variable needed)
-- Any node
MATCH (n) RETURN n
 
-- Labeled node
MATCH (n:Person) RETURN n.name
 
-- Labeled with property filter
MATCH (n:Person {city: 'Reykjavik'}) RETURN n.name
 
-- Anonymous (you don't need the value, just to confirm the pattern exists)
MATCH (:Company {name: 'Acme'})-[:HAS]->(d:Department) RETURN d.name

Relationship patterns#

A relationship pattern connects two nodes:

(a)-[r:TYPE {property: value}]->(b)
ElementMeaning
-[:KNOWS]->Directed relationship of type KNOWS
<-[:KNOWS]-Reverse direction
-[:KNOWS]-Either direction
-[r:KNOWS]->Bind to variable r to access properties
-[r]->Any relationship type
-[:KNOWS {since: 2020}]->Relationship with property filter
-- Directed
MATCH (a:Person)-[:KNOWS]->(b:Person) RETURN a.name, b.name
 
-- Either direction
MATCH (a:Person)-[:KNOWS]-(b:Person) RETURN a.name, b.name
 
-- With relationship properties
MATCH (a)-[r:KNOWS]->(b) WHERE r.since > 2019 RETURN a.name, b.name, r.since
 
-- Any relationship type
MATCH (a:Person)-[r]->(b) RETURN a.name, type(r), b.name

Variable-length paths#

Append *min..max to a relationship pattern to match paths of varying depth:

-- Exactly 2 hops
MATCH (a)-[:KNOWS*2]->(b) RETURN b.name
 
-- 1 to 3 hops
MATCH (a:Person {name: 'Alice'})-[:KNOWS*1..3]->(b) RETURN b.name
 
-- Any number of hops (use carefully on large graphs)
MATCH (a)-[:KNOWS*]->(b) RETURN b.name

This is where the power of graph patterns becomes obvious. The SQL equivalent requires a recursive CTE or a series of self-joins — one per hop depth. In GQL, you write it once.

-- SQL: "who does Alice know, up to 3 hops?"
WITH RECURSIVE knows AS (
  SELECT person_id, known_id, 1 as depth FROM relationships WHERE person_id = alice_id
  UNION ALL
  SELECT k.person_id, r.known_id, k.depth + 1
  FROM knows k JOIN relationships r ON k.known_id = r.person_id
  WHERE k.depth < 3
)
SELECT DISTINCT known_id FROM knows;
 
-- GQL: same thing
MATCH (alice:Person {name: 'Alice'})-[:KNOWS*1..3]->(b) RETURN DISTINCT b.name

Multi-pattern (implicit join)#

Multiple MATCH clauses in sequence find nodes that satisfy all patterns simultaneously:

-- Find a person AND a company independently (Cartesian product)
MATCH (p:Person {name: 'Alice'})
MATCH (c:Company {name: 'Acme'})
RETURN p.name, c.name
 
-- Find people who work at the same company as Alice
MATCH (alice:Person {name: 'Alice'})-[:WORKS_AT]->(c:Company)
MATCH (colleague:Person)-[:WORKS_AT]->(c)
WHERE colleague.name <> 'Alice'
RETURN colleague.name, c.name

OPTIONAL MATCH#

Like a SQL LEFT JOIN — returns the pattern match if it exists, null if it doesn't:

MATCH (p:Person)
OPTIONAL MATCH (p)-[:HAS_PHONE]->(ph:Phone)
RETURN p.name, ph.number  -- ph.number is null if no phone exists

Patterns in context: the mental shift from SQL#

In SQL, a many-to-many relationship requires a junction table and two JOINs. In GQL, it's just a traversal:

-- SQL: "find people who like the same movies"
SELECT a.name, b.name
FROM people a
JOIN likes al ON a.id = al.person_id
JOIN likes bl ON al.movie_id = bl.movie_id
JOIN people b ON bl.person_id = b.id
WHERE a.id <> b.id;
-- GQL: same question, no junction table needed
MATCH (a:Person)-[:LIKES]->(m:Movie)<-[:LIKES]-(b:Person)
WHERE a <> b
RETURN a.name, b.name, m.title

The GQL pattern directly mirrors how you'd draw the relationship on a whiteboard. The SQL query is an artifact of how the data is stored.

ArcFlow extensions to patterns#

WorldCypher adds pattern capabilities beyond the GQL standard:

Confidence filtering on relationships:

-- Only traverse edges the system is confident about
MATCH (a:Person)-[r:KNOWS]->(b)
WHERE r._confidence > 0.8
RETURN a.name, b.name, r._confidence

Temporal patterns — the graph as it existed before:

-- Who did Alice know 30 days ago?
MATCH (alice:Person {name: 'Alice'})-[:KNOWS]->(b) AS OF seq 1000
RETURN b.name

Live patterns — re-evaluate when the graph changes:

-- Standing query: fires when a new high-score person appears
LIVE MATCH (n:Person) WHERE n.score > 0.95 RETURN n.name, n.score

Further reading#

  • MATCH reference — full syntax and edge cases
  • Variable-length paths and shortestPath
  • WHERE reference — filtering patterns
  • SQL vs GQL — the full mental model shift
Try it
Open ↗⌘↵ to run
Loading engine…
← PreviousQuery Language (GQL)Next →SQL vs GQL