Cypher
Cypher is the main direct graph-query surface. Use it when you want precise graph patterns, explicit procedures, or a reproducible query to paste into the frontend Direct Query tab. See Cypher And openCypher Compatibility for the supported scope and Cypher Writes And Schema for governed mutations.
Direct Query Basics
In the frontend:
-
Select a database.
-
Open Direct Query.
-
Choose
Cypher. -
Paste a read-only query.
-
Run it and inspect the table result.
If a Cypher query returns an error like expected CONSTRUCT, the language selector is set to SPARQL.
Switch it to Cypher and run the query again.
Without a web console, submit the query text through ExecuteCypher as shown in Connect To ShrikeDB. The examples below are templates over the named labels and properties. For Person examples, load people with the referenced properties; healthcare examples require ClaimCell and Procedure data; path procedures require the indicated node IDs and relationship properties.
Core Syntax
Implemented practical syntax includes:
-
MATCH,OPTIONAL MATCH,WHERE, andRETURN; -
WITH, aggregation,DISTINCT, andUNWIND; -
UNIONandUNION ALL; -
null-aware expressions, lists, maps, comprehensions and bounded read-only subqueries;
-
ORDER BY,SKIP, andLIMIT; -
CALL … YIELDprocedures; -
CALL vector.knn(…); -
CALL kv.get(…); -
SEARCH collection AS alias; -
RANK rerank_v3(…); -
governed
CREATE,MERGE, property updates and node deletion; -
EXPLAIN,PROFILE, and scoped schema catalog commands; -
fixed and bounded named path materialization for supported shapes.
Use backticks around relationship or property names that contain ::
MATCH (cell:ClaimCell)-[:`tmsis:hasProcedure`]->(procedure:Procedure)
RETURN cell, procedure
LIMIT 10
Basic Graph Patterns
MATCH (n)
RETURN n
LIMIT 10
MATCH (cell:ClaimCell)-[:`tmsis:hasProcedure`]->(procedure:Procedure)
RETURN cell, procedure
LIMIT 25
Filtering And Aggregation
MATCH (cell:ClaimCell)-[:`tmsis:hasProcedure`]->(procedure:Procedure)
WHERE procedure = "urn:cms:tmsis:provider-spending:hcpcs:T1019"
RETURN procedure, count(*) AS cells
LIMIT 10
For semantic rollups that depend on profile-specific measures, the natural-language semantic surface may be more reliable than hand-written Cypher because it can use profile-defined aggregate fields.
Pipelines And Aggregation
WITH projects the bindings available to the next clause.
It can group rows, compute aggregates and filter their aliases before the final result:
MATCH (p:Person)
WITH p.country AS country, count(*) AS people
WHERE people > 1
RETURN country, people
ORDER BY people DESC
LIMIT 20
Use a second projection for arithmetic on an aggregate; nested aggregate expressions such as RETURN count(*) + 1 are outside the current lowering scope.
MATCH (p:Person)
WITH count(*) AS people
RETURN people + 1 AS next_count
Lists, UNWIND And DISTINCT
This example needs no graph data:
UNWIND [3, 1, 3, NULL] AS x
RETURN count(*) AS rows, count(x) AS present,
count(DISTINCT x) AS distinct_present,
collect(DISTINCT x) AS values
The counts are 4 rows, 3 non-null values and 2 distinct non-null values. The collection contains 1 and 3; do not rely on their order without an ordered pipeline. An empty global aggregate still returns one row, while an empty grouped result has no groups to return.
Optional Matches And Nulls
MATCH (p:Person)
OPTIONAL MATCH (p)-[:KNOWS]->(friend:Person)
RETURN p, count(friend) AS friends
LIMIT 20
The optional clause preserves a person with no matching friend and supplies a null friend binding.
count(friend) is zero for that row; count(*) would count the preserved row.
Keep an optional-side filter attached to its OPTIONAL MATCH when it should constrain the optional match rather than remove the preserved outer row.
A leading OPTIONAL MATCH without an existing row stream is outside the general planner’s scope.
RETURN NULL = NULL AS unknown_equality,
NULL IS NULL AS is_null,
coalesce(NULL, 'unknown') AS display_name,
CASE WHEN 2 IN [1, 2, 3] THEN 'present' ELSE 'absent' END AS membership
This returns null, true, unknown, and present respectively.
See Cypher And openCypher Compatibility for the full null and empty-aggregate rules.
Unions, Comprehensions And Subqueries
UNION removes duplicate rows; UNION ALL preserves them.
Use matching output column names in every branch and one union mode throughout the query:
RETURN 1 AS value
UNION ALL
RETURN 2 AS value
List comprehensions and quantified predicates also work without graph data:
RETURN [x IN [1, 2, 3] WHERE x > 1 | x + 10] AS shifted,
any(x IN [1, 2, 3] WHERE x > 2) AS has_large
The result is [12, 13] and true.
Fixed-pattern comprehensions and COUNT { … } / COLLECT { … } read-only expressions are also supported within bounded output limits.
COLLECT { … } must return one visible column; variable-length pattern comprehensions are rejected.
Use explicit imports for a correlated read-only subquery:
MATCH (p:Person)
CALL (p) {
MATCH (p)-[:KNOWS]->(friend)
RETURN friend
}
RETURN p, friend
LIMIT 20
A CALL branch with no output rows does not provide optional null extension.
To filter by existence without projecting each matching friend:
MATCH (p:Person)
WHERE EXISTS { MATCH (p)-[:KNOWS]->(friend) }
RETURN p
LIMIT 20
WHERE NOT EXISTS { … } is also supported.
These existence forms must be top-level WHERE predicates in the current implementation.
Subqueries are read-only; mutation, schema commands and UNION inside them are rejected.
Path Aliases And Path Functions
For supported fixed or bounded path shapes, ShrikeDB materializes path values.
MATCH p = (a)-[:KNOWS]->(b)
RETURN p, length(p), nodes(p), relationships(p)
LIMIT 10
MATCH p = (a)-[:KNOWS*1..3]->(b)
RETURN nodes(p), length(p)
ORDER BY length(p)
LIMIT 20
Ordinary bounded patterns also work without a path alias:
MATCH (a:Person)-[:KNOWS*0..3]->(b:Person)
RETURN count(DISTINCT b) AS reachable_people
0..3 includes zero hops; ..3 starts at one hop.
Bounded clauses enforce relationship uniqueness across their segments, allow node revisits through different edges, and check endpoint filters.
Separate MATCH clauses can reuse an edge.
Unbounded paths and unsupported relationship-variable bindings in bounded clauses are rejected rather than approximated.
Exceeding path/candidate limits is an error, not a partial count; see Cypher controls.
Graph Analytics Procedures
Graph analytics use GDS-like stream procedures. They are read-only in normal query mode.
CALL gds.pageRank.stream({
relationshipTypes: ["tmsis:hasProcedure"],
maxIterations: 10,
dampingFactor: 0.85,
topK: 10
})
YIELD nodeId, score
RETURN nodeId, score
LIMIT 10
CALL gds.wcc.stream({
relationshipTypes: ["tmsis:hasProcedure"]
})
YIELD nodeId, componentId
RETURN nodeId, componentId
LIMIT 10
Centrality examples:
CALL gds.degree.stream({
relationshipTypes: ["tmsis:hasServicingProvider"],
orientation: "REVERSE",
topK: 10
})
YIELD nodeId, degree, score
RETURN nodeId, degree, score
ORDER BY score DESC
LIMIT 10
CALL gds.betweenness.stream({
relationshipTypes: ["KNOWS"],
topK: 10,
sourceSampleSize: 256
})
YIELD nodeId, score
RETURN nodeId, score
ORDER BY score DESC
LIMIT 10
Weighted Path Procedures
Weighted path procedures run over finite numeric relationship weights.
They lower through the same path-query operator as the SPARQL SERVICE extensions.
CALL gds.shortestPath.dijkstra.stream({
sourceNode: "uid:1",
targetNode: "uid:42",
relationshipTypes: ["ROAD"],
relationshipWeightProperty: "cost"
})
YIELD targetNodeId, totalCost, nodeIds, costs, path
RETURN targetNodeId, totalCost, nodeIds, costs
CALL gds.shortestPath.astar.stream({
sourceNode: "uid:1",
targetNode: "uid:42",
relationshipTypes: ["ROAD"],
relationshipWeightProperty: "cost",
latitudeProperty: "lat",
longitudeProperty: "lon",
heuristicScale: 1.0,
fallbackToDijkstra: true
})
YIELD targetNodeId, totalCost, nodeIds, costs
RETURN targetNodeId, totalCost, nodeIds, costs
CALL gds.shortestPath.yens.stream({
sourceNode: "uid:1",
targetNode: "uid:42",
relationshipTypes: ["ROAD"],
relationshipWeightProperty: "cost",
k: 5
})
YIELD index, totalCost, nodeIds, costs
RETURN index, totalCost, nodeIds, costs
ORDER BY index
CALL gds.bellmanFord.stream({
sourceNode: "uid:1",
targetNodes: ["uid:42"],
relationshipTypes: ["ROAD"],
relationshipWeightProperty: "cost"
})
YIELD sourceNodeId, targetNodeId, distance, isNegativeCycle
RETURN sourceNodeId, targetNodeId, distance, isNegativeCycle
Multimodal Composition
CALL vector.knn("products_mm_vec", [0.031, -0.118, 0.442], 50, {ef: 256})
YIELD node AS product, score
MATCH (product:Product)-[:IN_CATEGORY]->(category:Category)
CALL kv.get("default", product) YIELD value AS product_json
RETURN product, category, score, product_json
LIMIT 12
Store product_json with PutKeyValue using the product UID as the key. The
string argument selects the public default KV namespace. See
Multimodal queries for the complete data setup and query flow.
Boundaries
The compatibility reference documents clause, expression, path and storage-semantic limits. When a query shape is not supported, prefer one of these paths:
-
simplify the graph pattern;
-
use a GDS-style procedure for a graph algorithm;
-
ask the semantic surface to compile a profile-backed query;
-
use SPARQL for RDF-shaped triple patterns.