Definition and Overview

Cypher is a declarative graph query language designed for expressive and efficient querying of property graph databases. Originally created by Andres Taylor at Neo Technology (now Neo4j, Inc.) in 2011, Cypher uses ASCII-art syntax to represent graph patterns, making queries visually intuitive for developers accustomed to thinking in terms of nodes and relationships. The language has been open-sourced as openCypher and adopted by multiple graph database vendors including KuzuDB, Memgraph, Amazon Neptune (limited), and RedisGraph.

The core design principle of Cypher is pattern matching. Rather than specifying how to traverse a graph (imperative), Cypher queries describe what pattern to find (declarative). The database engine determines the optimal execution strategy, much as SQL engines optimize relational queries. A Cypher query like MATCH (a:Person)-[:KNOWS]->(b:Person) RETURN a.name, b.name reads naturally as "find all pairs of persons where one knows the other."

Cypher's adoption as the de facto standard for property graph querying has been formalized through the GQL (Graph Query Language) ISO standard (ISO/IEC 39075), which draws heavily from Cypher's syntax and semantics. This standardization ensures that knowledge of Cypher transfers across graph database platforms, reducing vendor lock-in and enabling polyglot graph querying architectures.

Technical Deep Dive

Core Syntax Elements

ElementSyntaxDescription
Node(variable:Label {props})Represents a graph node with optional label and properties
Relationship-[variable:TYPE {props}]->Directed relationship with optional type and properties
Undirected-[variable:TYPE]-Relationship without direction constraint
Pattern(a)-[:REL]->(b)Complete pattern combining nodes and relationships
Variable-length(a)-[:REL*1..5]->(b)Path of 1 to 5 relationship hops

Clause Reference

ClausePurposeSQL Equivalent
MATCHFind patterns in the graphFROM + JOIN
WHEREFilter matched patternsWHERE
RETURNSpecify output columnsSELECT
CREATEInsert nodes and relationshipsINSERT
MERGEMatch or create (upsert)INSERT ... ON CONFLICT
DELETERemove nodes and relationshipsDELETE
SETUpdate propertiesUPDATE SET
WITHChain query parts (pipeline)CTE / subquery
UNWINDExpand list to rowsUNNEST / LATERAL
ORDER BYSort resultsORDER BY
LIMIT / SKIPPaginationLIMIT / OFFSET
OPTIONAL MATCHLeft outer join equivalentLEFT JOIN
UNIONCombine result setsUNION

Query Examples

// Find shortest path between two entities
MATCH path = shortestPath(
  (a:Entity {name: 'Company A'})-[*..6]-(b:Entity {name: 'Person B'})
)
RETURN path, length(path) AS hops

// Aggregate relationship counts by type
MATCH (e:Entity)-[r]->(target)
WHERE e.source = 'czech_registry'
RETURN type(r) AS relationship_type,
       count(r) AS count,
       collect(DISTINCT target.entity_type) AS target_types
ORDER BY count DESC

// Variable-length path with filtering
MATCH (company:Entity {entity_type: 'company'})
      -[:HAS_DIRECTOR*1..3]->(person:Entity {entity_type: 'person'})
WHERE company.country = 'CZ'
RETURN company.name, person.name,
       length(shortestPath((company)-[*]-(person))) AS distance

// MERGE for idempotent entity creation
MERGE (e:Entity {external_id: $external_id})
ON CREATE SET e.name = $name, e.created_at = datetime()
ON MATCH SET e.updated_at = datetime()
RETURN e

Architecture and Implementation

Cypher query execution follows a pipeline architecture: parsing produces an abstract syntax tree (AST), semantic analysis resolves variable bindings and validates label/relationship types, the query planner generates a logical plan, the optimizer selects physical operators and access methods, and the executor runs the plan against the storage engine.

The pattern matching engine is the heart of Cypher execution. For each MATCH clause, the engine must find all subgraph isomorphisms in the database that match the specified pattern. This is computationally equivalent to subgraph isomorphism testing (NP-complete in general), but practical query plans exploit indexes on node labels and relationship types, property value indexes, and join ordering heuristics to achieve acceptable performance on real-world graphs.

Graph databases use specialized storage formats optimized for relationship traversal. Unlike relational databases that require expensive joins, graph databases store relationships as direct pointers between nodes, enabling constant-time relationship traversal regardless of graph size. This "index-free adjacency" property is what makes graph databases efficient for deep traversals.

Usage in Prismatic Platform

The Prismatic Platform integrates Cypher through the KuzuDB storage adapter, using graph queries for OSINT entity resolution, relationship discovery, and network analysis in the DD (Due Diligence) pipeline.

defmodule PrismaticStorageKuzu.CypherQuery do
  @moduledoc """
  Cypher query builder and executor for KuzuDB integration.
  Used by the DD pipeline for entity relationship discovery
  and the OSINT toolbox for network analysis.
  """

  alias PrismaticStorageKuzu.Connection

  @type query_result :: {:ok, list(map())} | {:error, term()}

  @spec find_entity_network(String.t(), pos_integer()) :: query_result()
  def find_entity_network(entity_id, max_depth \\ 3) do
    cypher = """
    MATCH path = (source:Entity {id: $entity_id})-[*1..#{max_depth}]-(connected)
    RETURN connected.id AS id,
           connected.name AS name,
           connected.entity_type AS type,
           length(path) AS distance,
           [r IN relationships(path) | type(r)] AS relationship_chain
    ORDER BY distance ASC
    """

    Connection.execute(cypher, %{entity_id: entity_id})
  end

  @spec find_shortest_path(String.t(), String.t()) :: query_result()
  def find_shortest_path(from_id, to_id) do
    cypher = """
    MATCH path = shortestPath(
      (a:Entity {id: $from_id})-[*..10]-(b:Entity {id: $to_id})
    )
    RETURN [n IN nodes(path) | {id: n.id, name: n.name, type: n.entity_type}] AS nodes,
           [r IN relationships(path) | {type: type(r), properties: properties(r)}] AS edges,
           length(path) AS hops
    """

    Connection.execute(cypher, %{from_id: from_id, to_id: to_id})
  end

  @spec upsert_entity(map()) :: query_result()
  def upsert_entity(entity) do
    cypher = """
    MERGE (e:Entity {external_id: $external_id})
    ON CREATE SET e.name = $name,
                  e.entity_type = $entity_type,
                  e.source = $source,
                  e.created_at = $now
    ON MATCH SET e.name = $name,
                 e.updated_at = $now
    RETURN e.external_id AS id, e.name AS name
    """

    params = Map.put(entity, :now, DateTime.utc_now() |> DateTime.to_iso8601())
    Connection.execute(cypher, params)
  end
end

The DD pipeline's entity resolution process uses Cypher extensively for merging entities from multiple Czech registry sources, detecting duplicate entries through property similarity, and building relationship networks that reveal corporate ownership structures, board memberships, and beneficial ownership chains.

Cross-References

  • Graph Database -- Database model Cypher queries against
  • KuzuDB -- Embedded graph database used by the platform
  • Property Graph -- Data model underlying Cypher
  • SPARQL -- Alternative graph query language for RDF
  • Full-Text Index -- Text search complementing graph queries
  • Livebooks: storage_data/ notebooks demonstrate interactive Cypher querying
  • Academy: Topics referencing entity relationship analysis use Cypher examples

Connect & Contribute

Created by Tomas Korcak (korczis) | Open Source under GHL