Cypher Syntax Reference

MATCH, WHERE, WITH, RETURN, ORDER BY, aggregations, and path patterns — the Cypher language as supported by WhisperGraph.

Updated May 2026cypher Integration

Cypher Syntax Reference Documentation

The Cypher language clauses and operators supported by WhisperGraph. For schema details (labels, edge types, ER diagram) see the Graph Schema Reference. For functions and procedures see Functions & Procedures.

Language reference

MATCH

Basic pattern matching. Always anchor your starting node with {name: "value"} on large labels like HOSTNAME and IPV4.

MATCH (n:HOSTNAME {name: "www.google.com"}) RETURN n.name
MATCH (h:HOSTNAME {name: "www.google.com"})-[:RESOLVES_TO]->(ip:IPV4)
RETURN h.name, ip.name LIMIT 10

OPTIONAL MATCH

Returns null for unmatched patterns instead of dropping the row. Use this for WHOIS fields and other sparse data where not every node has every relationship.

MATCH (h:HOSTNAME {name: "www.google.com"})
OPTIONAL MATCH (h)-[:HAS_CERTIFICATE]->(c)
RETURN h.name, c.name

This returns one row with c.name as null, rather than zero rows.

WHERE clause

Comparison operators:

=, <>, <, >, <=, >=

MATCH (n:TLD) WHERE n.name <> "com" RETURN n.name LIMIT 3

String predicates:

-- Prefix search (fast, uses index)
MATCH (n:HOSTNAME) WHERE n.name STARTS WITH "www.googl" RETURN n.name LIMIT 5

-- Substring search (fast)
MATCH (n:HOSTNAME) WHERE n.name CONTAINS "cloudflare" RETURN n.name LIMIT 5

-- Suffix search (fast on HOSTNAME and TLD, slow on other labels)
MATCH (n:HOSTNAME) WHERE n.name ENDS WITH ".google.com" RETURN n.name LIMIT 5

Regular expressions:

MATCH (n:HOSTNAME) WHERE n.name =~ "www\\.google\\.com" RETURN n.name LIMIT 1

Regex uses full-match semantics (not substring). Nested quantifiers are rejected for safety. Maximum pattern length is 1000 characters. Prefer STARTS WITH, ENDS WITH, or CONTAINS instead of regex when possible.

Logical operators: AND, OR, NOT, XOR

WITH 5 AS x WHERE x > 3 AND x < 10 RETURN x

NULL checks: IS NULL, IS NOT NULL

WITH null AS x RETURN x IS NULL AS result

List membership: IN

MATCH (n:ASN) WHERE n.name IN ["AS13335", "AS15169"] RETURN n.name

RETURN

Projects columns from matched patterns. Supports aliases with AS and DISTINCT.

MATCH (h:HOSTNAME {name: "www.google.com"})-[:RESOLVES_TO]->(ip)
RETURN DISTINCT ip.name AS address
MATCH (h:HOSTNAME {name: "www.google.com"})-[:RESOLVES_TO]->(ip)
WITH h.name AS host, collect(ip.name) AS ips
RETURN host, ips

WITH

Pipes results between query stages. You can aggregate, filter, and reshape data mid-query.

MATCH (h:HOSTNAME {name: "www.google.com"})-[:RESOLVES_TO]->(ip)
WITH h.name AS host, count(ip) AS ipCount
RETURN host, ipCount
MATCH (sub:HOSTNAME)-[:CHILD_OF]->(h:HOSTNAME {name: "github.com"})
WITH sub LIMIT 5000
MATCH (sub)-[:RESOLVES_TO]->(ip:IPV4)
RETURN DISTINCT ip.name LIMIT 30

ORDER BY, LIMIT, SKIP

Sort results and paginate. Always use LIMIT on queries against large labels.

MATCH (n:TLD) RETURN n.name ORDER BY n.name ASC LIMIT 5
MATCH (n:COUNTRY) RETURN n.name ORDER BY n.name SKIP 2 LIMIT 3

Both SKIP N LIMIT M and LIMIT M SKIP N orderings are supported.

UNWIND

Turns a list into individual rows. This is the batch lookup pattern.

UNWIND ["google.com", "cloudflare.com", "microsoft.com"] AS domain
MATCH (h:HOSTNAME {name: domain})
OPTIONAL MATCH (h)-[:HAS_REGISTRAR]->(r:REGISTRAR)
RETURN domain, collect(DISTINCT r.name) AS registrars

You can pass dozens or hundreds of indicators in a single UNWIND list.

UNION

Combines results from multiple MATCH clauses. UNION deduplicates; UNION ALL keeps duplicates.

MATCH (n:TLD {name: "com"}) RETURN n.name
UNION
MATCH (n:TLD {name: "net"}) RETURN n.name

CALL subqueries

Correlated subqueries import variables with WITH.

MATCH (h:HOSTNAME {name: "www.google.com"})
CALL { WITH h MATCH (h)-[:RESOLVES_TO]->(ip) RETURN count(ip) AS ipCount }
RETURN h.name, ipCount

CALL is also used to invoke procedures:

CALL explain("185.220.101.1")
CALL whisper.history("cloudflare.com")
CALL whisper.quota()
CALL db.labels()
CALL db.relationshipTypes()

EXPLAIN

Shows the query plan without executing the query.

EXPLAIN MATCH (h:HOSTNAME {name: "www.google.com"})-[:RESOLVES_TO]->(ip) RETURN ip.name
ProduceResult([ip.name])
  Project([ip.name])
    Expand(h-[RESOLVES_TO]->ip)
      NodeLookup(h={name:'www.google.com'}:HOSTNAME)

Use EXPLAIN to verify the engine is using an indexed lookup rather than a label scan. PROFILE returns the same plan plus row counts per operator.

CASE / WHEN

Conditional expressions.

RETURN CASE WHEN 1 > 0 THEN "positive" ELSE "negative" END AS result
MATCH (h:HOSTNAME {name: "cloudflare.com"})-[:RESOLVES_TO]->(ip:IPV4)
OPTIONAL MATCH (ip)-[:LISTED_IN]->(f:FEED_SOURCE)
RETURN ip.name,
       CASE WHEN f IS NOT NULL THEN "listed" ELSE "clean" END AS status
LIMIT 5

Nested CASE expressions are supported.

shortestPath

Finds the minimum-hop path between two nodes.

MATCH (a:HOSTNAME {name: "cloudflare.com"}), (b:HOSTNAME {name: "google.com"})
MATCH p = shortestPath((a)-[*1..6]-(b))
RETURN length(p) AS hops, [n IN nodes(p) | n.name] AS path

Always specify a bounded path length like [*1..6]. Unbounded paths may be slow or time out. allShortestPaths() is also supported and returns all paths of the shortest length.

EXISTS subqueries

MATCH (h:HOSTNAME {name: "www.google.com"})
WHERE EXISTS { (h)-[:RESOLVES_TO]->() }
RETURN h.name

The function-style EXISTS(expr) predicate is also supported. It returns true if the expression is non-null:

MATCH (h:HOSTNAME {name: "google.com"}) RETURN EXISTS(h.name) AS has_name

COUNT subqueries

MATCH (h:HOSTNAME {name: "www.google.com"})
RETURN h.name, COUNT { (h)-[:RESOLVES_TO]->() } AS ipCount

Note: COUNT{}, COLLECT{}, and EXISTS{} subqueries cannot be used directly in ORDER BY. Pre-compute in a WITH clause, then sort by the alias.

COLLECT subqueries

MATCH (h:HOSTNAME {name: "www.google.com"})
RETURN h.name, COLLECT { MATCH (h)-[:RESOLVES_TO]->(ip) RETURN ip.name } AS ips

List comprehensions

RETURN [x IN range(1, 10) WHERE x % 2 = 0] AS evens
WITH [1, 2, 3, 4, 5] AS nums
RETURN [x IN nums WHERE x > 2 | x * 10] AS filtered

Pattern comprehensions

MATCH (h:HOSTNAME {name: "www.google.com"})
RETURN h.name, [(h)-[:RESOLVES_TO]->(ip) | ip.name] AS ips