Cypher Query Language¶
Uni supports a substantial subset of the OpenCypher query language, optimized for vectorized execution. This guide covers all supported syntax with practical examples.
Overview¶
Cypher is a declarative graph query language that uses ASCII-art patterns to describe graph structures:
// Pattern: (startNode)-[relationship]->(endNode)
MATCH (person:Person)-[:KNOWS]->(friend:Person)
WHERE person.age > 30
RETURN friend.name
Query Structure¶
A complete Cypher query follows this structure:
[MATCH clause] -- Pattern matching
[WHERE clause] -- Filtering
[WITH clause] -- Intermediate processing
[RETURN clause] -- Output projection
[ORDER BY clause] -- Sorting
[SKIP/LIMIT clause] -- Pagination
Example Query¶
MATCH (p:Paper)-[:AUTHORED_BY]->(a:Author)
WHERE p.year >= 2020 AND a.affiliation = 'MIT'
RETURN p.title, a.name, p.year
ORDER BY p.year DESC
LIMIT 10
MATCH Clause¶
The MATCH clause specifies graph patterns to find.
Node Patterns¶
// Any node
MATCH (n)
// Node with label
MATCH (p:Paper)
// Node with multiple labels (future)
MATCH (n:Paper:Preprint)
// Node with variable binding
MATCH (paper:Paper)
RETURN paper.title
// Anonymous node (no variable)
MATCH (:Paper)-[:CITES]->(cited)
RETURN cited.title
Node Properties in Pattern¶
// Filter in pattern (equivalent to WHERE)
MATCH (p:Paper {year: 2023})
RETURN p.title
// Multiple properties
MATCH (p:Paper {year: 2023, venue: 'NeurIPS'})
RETURN p.title
Relationship Patterns¶
// Outgoing relationship
MATCH (a)-[:KNOWS]->(b)
// Incoming relationship
MATCH (a)<-[:KNOWS]-(b)
// Either direction
MATCH (a)-[:KNOWS]-(b)
// Any relationship type
MATCH (a)-[r]->(b)
// Relationship with variable
MATCH (p:Paper)-[c:CITES]->(cited:Paper)
RETURN c // Access edge properties
Multi-Hop Patterns¶
// 2-hop path
MATCH (a:Paper)-[:CITES]->(b:Paper)-[:CITES]->(c:Paper)
RETURN a.title, b.title, c.title
// Chain multiple relationships
MATCH (p:Paper)-[:AUTHORED_BY]->(a:Author)-[:AFFILIATED_WITH]->(u:University)
RETURN p.title, a.name, u.name
Variable-Length Paths¶
Variable-length path patterns allow traversing multiple hops in a single pattern.
// 1 to 3 hops
MATCH (a:Paper)-[:CITES*1..3]->(b:Paper)
RETURN a.title, b.title
// Exactly 2 hops
MATCH (a)-[:KNOWS*2]->(b)
// Any length (use with caution on large graphs)
MATCH (a)-[:KNOWS*]->(b)
// Zero or more hops
MATCH (a)-[:KNOWS*0..]->(b)
// With path variable
MATCH path = (a:Paper)-[:CITES*1..5]->(b:Paper)
WHERE a.title = 'Attention Is All You Need'
RETURN path, length(path) AS hops
WHERE Clause¶
The WHERE clause filters matched patterns.
Comparison Operators¶
// Equality
WHERE p.year = 2023
// Inequality
WHERE p.year <> 2020
WHERE p.year != 2020
// Comparison
WHERE p.year > 2020
WHERE p.year >= 2020
WHERE p.year < 2025
WHERE p.year <= 2025
Boolean Logic¶
// AND
WHERE p.year > 2020 AND p.venue = 'NeurIPS'
// OR
WHERE p.venue = 'NeurIPS' OR p.venue = 'ICML'
// NOT
WHERE NOT p.is_retracted
// Parentheses for grouping
WHERE (p.year > 2020 AND p.venue = 'NeurIPS') OR p.citations > 1000
NULL Handling¶
// Check for NULL
WHERE p.doi IS NULL
WHERE p.doi IS NOT NULL
// COALESCE (use default if NULL)
RETURN COALESCE(p.nickname, p.name) AS display_name
String Operations¶
// Starts with
WHERE p.title STARTS WITH 'Attention'
// Ends with
WHERE p.title ENDS WITH 'Networks'
// Contains (uses JSON FTS index if available)
WHERE p.title CONTAINS 'Transformer'
// Full-text search on JSON document column (requires JSON FTS index)
WHERE a._doc CONTAINS 'graph database'
// Path-specific JSON FTS search
WHERE a._doc.title CONTAINS 'graph'
// Regular expression (future)
WHERE p.title =~ '.*Transform.*'
Note: The CONTAINS operator is automatically routed to JSON FTS indexes when the column has an FTS index, enabling BM25-based full-text search with relevance ranking.
List Operations¶
// IN list
WHERE p.venue IN ['NeurIPS', 'ICML', 'ICLR']
// NOT IN
WHERE p.venue NOT IN ['Workshop', 'Demo']
Property Existence¶
RETURN Clause¶
The RETURN clause specifies output columns.
Basic Projections¶
// Single property
RETURN p.title
// Multiple properties
RETURN p.title, p.year, p.venue
// All properties (*)
RETURN p.*
// Entire node
RETURN p
Aliases¶
// AS keyword
RETURN p.title AS paper_title, a.name AS author_name
// Expression aliases
RETURN p.year + 1 AS next_year
Expressions¶
// Arithmetic
RETURN p.citations * 2 AS double_citations
// String concatenation
RETURN p.title + ' (' + p.venue + ')' AS formatted
// Conditional (CASE)
RETURN CASE
WHEN p.citations > 1000 THEN 'High Impact'
WHEN p.citations > 100 THEN 'Medium Impact'
ELSE 'Low Impact'
END AS impact_level
DISTINCT¶
// Remove duplicates
RETURN DISTINCT p.venue
// Distinct combinations
RETURN DISTINCT p.venue, p.year
Aggregations¶
Uni supports standard aggregation functions.
Aggregation Functions¶
| Function | Description | Example |
|---|---|---|
COUNT(*) |
Count all rows | RETURN COUNT(*) |
COUNT(x) |
Count non-null values | RETURN COUNT(p.doi) |
COUNT(DISTINCT x) |
Count distinct values | RETURN COUNT(DISTINCT p.venue) |
SUM(x) |
Sum numeric values | RETURN SUM(p.citations) |
AVG(x) |
Average | RETURN AVG(p.citations) |
MIN(x) |
Minimum | RETURN MIN(p.year) |
MAX(x) |
Maximum | RETURN MAX(p.year) |
COLLECT(x) |
Collect into list | RETURN COLLECT(p.title) |
Implicit Grouping¶
Non-aggregated columns become GROUP BY keys:
// Group by venue, count papers per venue
MATCH (p:Paper)
RETURN p.venue, COUNT(p) AS paper_count
ORDER BY paper_count DESC
Aggregation Examples¶
// Count papers per author
MATCH (p:Paper)-[:AUTHORED_BY]->(a:Author)
RETURN a.name, COUNT(p) AS papers, AVG(p.citations) AS avg_citations
ORDER BY papers DESC
// Most cited papers per venue
MATCH (p:Paper)
RETURN p.venue, MAX(p.citations) AS top_citations, COUNT(p) AS total
ORDER BY top_citations DESC
Window Functions¶
Window functions perform calculations across a set of rows related to the current row, without collapsing results like aggregations.
Basic Syntax¶
function_name(args) OVER (
[PARTITION BY partition_expr, ...]
[ORDER BY order_expr [ASC|DESC], ...]
)
Supported Window Functions¶
| Function | Description | Example |
|---|---|---|
row_number() |
Sequential row number | row_number() OVER (ORDER BY p.year) |
rank() |
Rank with gaps for ties | rank() OVER (ORDER BY p.citations DESC) |
dense_rank() |
Rank without gaps | dense_rank() OVER (ORDER BY p.citations DESC) |
sum() |
Running sum | sum(p.citations) OVER (ORDER BY p.year) |
avg() |
Running average | avg(p.citations) OVER (PARTITION BY p.venue) |
count() |
Running count | count(*) OVER (PARTITION BY p.venue) |
min() / max() |
Running min/max | max(p.citations) OVER (PARTITION BY p.author) |
Examples¶
Ranking within partitions:
MATCH (p:Paper)
RETURN p.title, p.venue, p.citations,
rank() OVER (PARTITION BY p.venue ORDER BY p.citations DESC) AS venue_rank
ORDER BY p.venue, venue_rank
Running totals:
MATCH (p:Paper)
WHERE p.author = 'Alice'
RETURN p.title, p.year, p.citations,
sum(p.citations) OVER (ORDER BY p.year) AS cumulative_citations
ORDER BY p.year
Top N per group:
MATCH (p:Paper)
WITH p, row_number() OVER (PARTITION BY p.venue ORDER BY p.citations DESC) AS rn
WHERE rn <= 3
RETURN p.venue, p.title, p.citations
ORDER BY p.venue, p.citations DESC
Scalar Functions¶
Uni provides a comprehensive set of scalar functions for data transformation.
String Functions¶
| Function | Description | Example |
|---|---|---|
toUpper(s) / upper(s) |
Convert to uppercase | RETURN toUpper('hello') → 'HELLO' |
toLower(s) / lower(s) |
Convert to lowercase | RETURN toLower('HELLO') → 'hello' |
trim(s) |
Remove leading/trailing whitespace | RETURN trim(' hi ') → 'hi' |
ltrim(s) |
Remove leading whitespace | RETURN ltrim(' hi') → 'hi' |
rtrim(s) |
Remove trailing whitespace | RETURN rtrim('hi ') → 'hi' |
substring(s, start, [len]) |
Extract substring | RETURN substring('hello', 1, 3) → 'ell' |
left(s, n) |
First n characters | RETURN left('hello', 2) → 'he' |
right(s, n) |
Last n characters | RETURN right('hello', 2) → 'lo' |
reverse(s) |
Reverse string | RETURN reverse('hello') → 'olleh' |
replace(s, old, new) |
Replace occurrences | RETURN replace('hello', 'l', 'x') → 'hexxo' |
split(s, delim) |
Split into list | RETURN split('a,b,c', ',') → ['a','b','c'] |
lpad(s, len, [pad]) |
Pad left to length | RETURN lpad('5', 3, '0') → '005' |
rpad(s, len, [pad]) |
Pad right to length | RETURN rpad('5', 3, '0') → '500' |
Math Functions¶
| Function | Description | Example |
|---|---|---|
abs(n) |
Absolute value | RETURN abs(-5) → 5 |
ceil(n) |
Round up | RETURN ceil(4.2) → 5 |
floor(n) |
Round down | RETURN floor(4.8) → 4 |
round(n) |
Round to nearest | RETURN round(4.5) → 5 |
sqrt(n) |
Square root | RETURN sqrt(16) → 4 |
sign(n) |
Sign (-1, 0, 1) | RETURN sign(-5) → -1 |
log(n) |
Natural logarithm | RETURN log(2.718) → ~1 |
log10(n) |
Base-10 logarithm | RETURN log10(100) → 2 |
exp(n) |
e^n | RETURN exp(1) → ~2.718 |
power(base, exp) / pow(base, exp) |
Exponentiation | RETURN power(2, 3) → 8 |
sin(n), cos(n), tan(n) |
Trigonometric | RETURN sin(0) → 0 |
List Functions¶
| Function | Description | Example |
|---|---|---|
size(list) |
Length of list/string/map | RETURN size([1,2,3]) → 3 |
head(list) |
First element | RETURN head([1,2,3]) → 1 |
tail(list) |
All but first element | RETURN tail([1,2,3]) → [2,3] |
last(list) |
Last element | RETURN last([1,2,3]) → 3 |
keys(map) |
Keys of a map | RETURN keys({a:1, b:2}) → ['a','b'] |
range(start, end, [step]) |
Generate number sequence | RETURN range(1, 5) → [1,2,3,4,5] |
Path Functions¶
| Function | Description | Example |
|---|---|---|
length(path) |
Number of relationships in path | RETURN length(path) |
nodes(path) |
List of nodes in path | RETURN nodes(path) |
relationships(path) |
List of relationships in path | RETURN relationships(path) |
Type Conversion Functions¶
| Function | Description | Example |
|---|---|---|
toInteger(x) |
Convert to integer | RETURN toInteger('42') → 42 |
toFloat(x) |
Convert to float | RETURN toFloat('3.14') → 3.14 |
toString(x) |
Convert to string | RETURN toString(42) → '42' |
toBoolean(x) |
Convert to boolean | RETURN toBoolean('true') → true |
Null Handling Functions¶
| Function | Description | Example |
|---|---|---|
coalesce(x, y, ...) |
First non-null value | RETURN coalesce(null, 'default') → 'default' |
nullif(a, b) |
Return null if a = b | RETURN nullif(5, 5) → null |
Example Usage¶
// String manipulation
MATCH (p:Paper)
RETURN toUpper(p.title) AS upper_title,
substring(p.abstract, 0, 100) AS abstract_preview
// Math operations
MATCH (p:Paper)
RETURN p.title, round(p.citations / 10.0) * 10 AS rounded_citations
// List operations
MATCH (a:Author)
WHERE size(a.affiliations) > 1
RETURN a.name, head(a.affiliations) AS primary_affiliation
// Type conversion
MATCH (p:Paper)
WHERE toInteger(p.year_str) > 2020
RETURN p.title
ORDER BY, SKIP, LIMIT¶
Sorting¶
// Ascending (default)
ORDER BY p.year
// Descending
ORDER BY p.year DESC
// Multiple columns
ORDER BY p.year DESC, p.title ASC
// By alias
RETURN p.title, p.citations AS cites
ORDER BY cites DESC
Pagination¶
// First 10 results
LIMIT 10
// Skip first 20, take next 10
SKIP 20
LIMIT 10
// Combined
RETURN p.title
ORDER BY p.year DESC
SKIP 100
LIMIT 25
CREATE Clause¶
Create new nodes and relationships.
Creating Nodes¶
// Simple node
CREATE (p:Paper {title: 'My Paper'})
// With properties
CREATE (p:Paper {
title: 'New Research',
year: 2024,
venue: 'ArXiv',
citations: 0
})
RETURN p
// Multiple nodes
CREATE (a:Author {name: 'Alice'}), (b:Author {name: 'Bob'})
Creating Relationships¶
// Between existing nodes
MATCH (p:Paper {title: 'Paper A'}), (a:Author {name: 'Alice'})
CREATE (p)-[:AUTHORED_BY {position: 1}]->(a)
// Create node and relationship together
CREATE (p:Paper {title: 'New Paper'})-[:AUTHORED_BY]->(a:Author {name: 'New Author'})
Returning Created Elements¶
WITH Clause¶
The WITH clause chains query parts together.
Intermediate Processing¶
// Filter after aggregation
MATCH (p:Paper)-[:AUTHORED_BY]->(a:Author)
WITH a, COUNT(p) AS paper_count
WHERE paper_count > 5
RETURN a.name, paper_count
Subquery-like Behavior¶
// First find top authors, then their papers
MATCH (a:Author)<-[:AUTHORED_BY]-(p:Paper)
WITH a, COUNT(p) AS papers
ORDER BY papers DESC
LIMIT 10
MATCH (a)<-[:AUTHORED_BY]-(recent:Paper)
WHERE recent.year >= 2022
RETURN a.name, recent.title
UNWIND Clause¶
Expand a list into individual rows.
// Expand literal list
UNWIND [1, 2, 3] AS num
RETURN num
// Expand list property
MATCH (p:Paper)
UNWIND p.keywords AS keyword
RETURN keyword, COUNT(*) AS usage
ORDER BY usage DESC
// Create multiple from list
UNWIND ['Alice', 'Bob', 'Charlie'] AS name
CREATE (a:Author {name: name})
CALL Clause (Procedures)¶
Invoke built-in procedures.
Vector Search¶
// Basic vector search
CALL db.idx.vector.query('Paper', 'embedding', $query_vector, 10)
YIELD node, distance
RETURN node.title, distance
// With threshold
CALL db.idx.vector.query('Paper', 'embedding', $query_vector, 100, 0.3)
YIELD node, distance
WHERE distance < 0.2
RETURN node.title, distance
Schema Introspection¶
// List labels
CALL db.labels()
YIELD label
RETURN label
// List relationship types
CALL db.relationshipTypes()
YIELD relationshipType
RETURN relationshipType
// List indexes
CALL db.indexes()
YIELD name, type, labelsOrTypes, properties
RETURN *
Index Management¶
Create Indexes¶
// Scalar index
CREATE INDEX ON :Paper(year)
// Named index
CREATE INDEX paper_year FOR (p:Paper) ON (p.year)
// Vector index
CREATE VECTOR INDEX paper_embeddings
FOR (p:Paper) ON p.embedding
OPTIONS {index_type: 'hnsw', metric: 'cosine'}
// JSON Full-Text index
CREATE JSON FULLTEXT INDEX article_fts
FOR (a:Article) ON _doc
OPTIONS {with_positions: true}
Drop Indexes¶
Show Indexes¶
Query Parameters¶
Use parameters to avoid injection and improve plan caching.
Parameter Syntax¶
CLI Usage¶
uni query "MATCH (p:Paper) WHERE p.year = \$year RETURN p" \
--params '{"year": 2023}' \
--path ./storage
Session Variables¶
Session variables provide scoped context that's automatically available in all queries within a session. This is ideal for multi-tenant applications.
Creating a Session¶
// Rust API
let session = db.session()
.set("tenant_id", "acme-corp")
.set("user_id", "user-123")
.set("granted_tags", vec!["public", "team:eng"])
.build();
Using Session Variables¶
Access session variables with the $session. prefix:
// Automatic tenant filtering
MATCH (d:Document)
WHERE d.tenant_id = $session.tenant_id
RETURN d.title
// Multiple session variables
MATCH (e:Event)
WHERE e.tenant_id = $session.tenant_id
AND e.created_by = $session.user_id
RETURN e
// Combining session variables with query parameters
MATCH (d:Document)
WHERE d.tenant_id = $session.tenant_id
AND d.status = $status
RETURN d
Session Variable Benefits¶
| Benefit | Description |
|---|---|
| Reduced boilerplate | No need to pass tenant_id to every query |
| Security | Variables are immutable after session creation |
| Consistency | Same context applied to all queries in session |
| Multi-tenancy | Natural pattern for SaaS applications |
Session Queries vs Regular Queries¶
// Without session (repetitive)
db.query_with("MATCH (d:Document) WHERE d.tenant = $t RETURN d")
.param("t", "acme")
.fetch_all().await?;
// With session (cleaner)
let session = db.session().set("tenant", "acme").build();
session.query("MATCH (d:Document) WHERE d.tenant = $session.tenant RETURN d").await?;
Temporal Queries¶
Uni provides functions for querying temporal (time-based) data with validity ranges.
validAt Function¶
Check if a node or edge was valid at a specific point in time:
// Basic validAt usage
MATCH (e:Event)
WHERE uni.validAt(e, 'valid_from', 'valid_to', datetime($time))
RETURN e.name, e.valid_from, e.valid_to
Parameters:
- e: Node or edge to check
- 'valid_from': Property name for start time
- 'valid_to': Property name for end time
- datetime($time): Point in time to check
Semantics: valid_from <= time < valid_to (half-open interval)
VALID_AT Macro¶
For convenience, use the VALID_AT macro with default property names:
// Macro form (uses 'valid_from' and 'valid_to' by default)
MATCH (e:Event)
WHERE e VALID_AT datetime('2024-06-15T12:00:00Z')
RETURN e.name
Custom Property Names¶
Specify custom property names if your schema differs:
// With custom property names
MATCH (c:Contract)
WHERE c VALID_AT(datetime($check_time), 'start_date', 'end_date')
RETURN c.name, c.value
Temporal Query Patterns¶
Find currently valid records:
MATCH (e:Employee)
WHERE uni.validAt(e, 'hire_date', 'termination_date', datetime())
RETURN e.name, e.department
Find records valid at a historical point:
MATCH (p:Price)
WHERE p.product_id = $product_id
AND uni.validAt(p, 'effective_from', 'effective_to', datetime('2024-01-01'))
RETURN p.amount
Temporal edges:
MATCH (e:Employee)-[r:WORKS_IN]->(d:Department)
WHERE uni.validAt(r, 'start_date', 'end_date', datetime($as_of_date))
RETURN e.name, d.name
Open-ended validity (NULL end date):
// Records with NULL valid_to are considered currently valid
MATCH (m:Membership)
WHERE m.valid_to IS NULL
OR m.valid_to > datetime()
RETURN m
DELETE Clause¶
Remove nodes and relationships from the graph.
Deleting Relationships¶
// Delete a specific relationship
MATCH (a:Author)-[r:AUTHORED]->(p:Paper)
WHERE a.name = 'Alice' AND p.title = 'Old Paper'
DELETE r
// Delete all relationships of a type
MATCH ()-[r:DEPRECATED]->()
DELETE r
Deleting Nodes¶
// Delete a node (must have no relationships)
MATCH (p:Paper {title: 'Deleted Paper'})
DELETE p
// Delete node and all its relationships (DETACH)
MATCH (p:Paper {title: 'Deleted Paper'})
DETACH DELETE p
// Delete multiple nodes
MATCH (p:Paper)
WHERE p.year < 1990
DETACH DELETE p
Conditional Deletion¶
// Delete only if condition is met
MATCH (p:Paper)
WHERE p.citations = 0 AND p.year < 2000
DETACH DELETE p
RETURN COUNT(*) AS deleted_count
UNION Clause¶
Combine results from multiple queries.
UNION (Distinct)¶
// Combine results, removing duplicates
MATCH (a:Author {affiliation: 'MIT'})
RETURN a.name AS name
UNION
MATCH (a:Author {affiliation: 'Stanford'})
RETURN a.name AS name
UNION ALL (Keep Duplicates)¶
// Combine results, keeping all rows
MATCH (p:Paper)-[:CITES]->(:Paper {title: 'Paper A'})
RETURN p.title AS title
UNION ALL
MATCH (p:Paper)-[:CITES]->(:Paper {title: 'Paper B'})
RETURN p.title AS title
Multi-way UNION¶
// Combine multiple queries
MATCH (a:Author) WHERE a.h_index > 50
RETURN a.name AS name, 'high_impact' AS category
UNION
MATCH (a:Author) WHERE a.papers > 100
RETURN a.name AS name, 'prolific' AS category
UNION
MATCH (a:Author) WHERE a.citations > 10000
RETURN a.name AS name, 'highly_cited' AS category
WITH RECURSIVE Clause¶
Execute recursive queries using Common Table Expressions (CTEs).
Basic Recursive Query¶
// Find all transitive citations (papers cited by cited papers)
WITH RECURSIVE citation_chain AS (
// Base case: direct citations
MATCH (p:Paper {title: 'Root Paper'})-[:CITES]->(cited:Paper)
RETURN cited
UNION
// Recursive case: citations of citations
MATCH (c:citation_chain)-[:CITES]->(next:Paper)
RETURN next
)
MATCH (p:citation_chain)
RETURN p.title
Recursive Path Finding¶
// Find all ancestors in a hierarchy
WITH RECURSIVE ancestors AS (
MATCH (n:Category {name: 'Machine Learning'})
RETURN n
UNION
MATCH (a:ancestors)-[:PARENT]->(parent:Category)
RETURN parent
)
MATCH (a:ancestors)
RETURN a.name AS category_hierarchy
EXPLAIN Clause¶
Inspect the query execution plan without running the query.
Basic EXPLAIN¶
// Show query plan
EXPLAIN MATCH (p:Paper)-[:CITES]->(cited:Paper)
WHERE p.year > 2020
RETURN cited.title, COUNT(*) AS citation_count
ORDER BY citation_count DESC
LIMIT 10
Understanding the Plan¶
The EXPLAIN output shows: - Scan operations: How data is accessed (index scan, full scan) - Filter operations: Where predicates are applied - Join operations: How patterns are matched - Aggregation: Grouping and aggregation steps - Sort/Limit: Final ordering and pagination - Index usage: Which indexes are used and why - Cost estimates: Estimated rows and query cost
EXPLAIN Output Example¶
Plan:
├─ Scan: Paper
│ ├─ Filter: year > 2020
│ │ └─ Index: paper_year_btree (BTREE) ✓
│ ├─ Estimated rows: 500
│ └─ Cost: 12.5
├─ Expand: CITES (OUTGOING)
│ ├─ Estimated paths: 2500
│ └─ Cost: 125.0
└─ Target: Paper
└─ Estimated rows: 2500
Index Usage:
✓ Paper.year → paper_year_btree (BTREE)
✗ Paper.venue → paper_venue_idx (not in filter)
Total estimated cost: 137.5
PROFILE Clause¶
Execute the query with runtime statistics collection.
Basic PROFILE¶
// Execute and collect statistics
PROFILE MATCH (p:Paper)-[:CITES]->(cited:Paper)
WHERE p.year > 2020
RETURN cited.title, COUNT(*) AS citation_count
ORDER BY citation_count DESC
LIMIT 10
PROFILE Output¶
PROFILE returns detailed execution metrics:
Execution Profile:
├─ Scan: Paper
│ ├─ Actual rows: 423
│ ├─ Time: 12.3ms
│ └─ Index hits: 423
├─ Expand: CITES
│ ├─ Actual paths: 1892
│ └─ Time: 45.6ms
└─ Project
├─ Actual rows: 1892
└─ Time: 1.2ms
Summary:
Total time: 59.1ms
Peak memory: 2.4MB
Rows returned: 1892
Using PROFILE for Optimization¶
// Compare two query approaches
PROFILE MATCH (a:Author)-[:AUTHORED]->(p:Paper)
WHERE a.name = 'Alice' AND p.year > 2020
RETURN p.title
// vs
PROFILE MATCH (p:Paper)
WHERE p.year > 2020
MATCH (a:Author {name: 'Alice'})-[:AUTHORED]->(p)
RETURN p.title
Common Query Patterns¶
Find Connected Nodes¶
MATCH (start:Paper {title: 'Attention Is All You Need'})
MATCH (start)-[:CITES]->(cited)
RETURN cited.title, cited.year
ORDER BY cited.year DESC
Bidirectional Relationships¶
// Papers that cite each other
MATCH (a:Paper)-[:CITES]->(b:Paper)-[:CITES]->(a)
RETURN a.title, b.title
Shortest Path (Future)¶
// Shortest path between two nodes
MATCH path = shortestPath((a:Author {name: 'Alice'})-[:COAUTHOR*]-(b:Author {name: 'Bob'}))
RETURN path
Degree Counting¶
// Count outgoing relationships
MATCH (p:Paper)-[c:CITES]->()
RETURN p.title, COUNT(c) AS out_degree
ORDER BY out_degree DESC
Top-K with Ties¶
Graph Algorithms¶
Uni provides 36 high-performance graph algorithms available via the algo namespace.
Centrality Algorithms¶
| Algorithm | Procedure | Description |
|---|---|---|
| PageRank | algo.pageRank |
Importance based on incoming links |
| Betweenness | algo.betweenness |
Nodes on shortest paths |
| Closeness | algo.closeness |
Average distance to all nodes |
| Degree Centrality | algo.degreeCentrality |
Connection count |
| Harmonic Centrality | algo.harmonicCentrality |
Harmonic mean distance |
| Eigenvector Centrality | algo.eigenvectorCentrality |
Influence via neighbors |
| Katz Centrality | algo.katzCentrality |
Weighted path influence |
// PageRank
CALL algo.pageRank(['Paper'], ['CITES'])
YIELD nodeId, score
RETURN nodeId, score
ORDER BY score DESC
// Betweenness Centrality
CALL algo.betweenness(['Author'], ['COAUTHOR'], true, 100)
YIELD nodeId, score
// Closeness Centrality
CALL algo.closeness(['Station'], ['CONNECTS'])
YIELD nodeId, score
Community Detection Algorithms¶
| Algorithm | Procedure | Description |
|---|---|---|
| Louvain | algo.louvain |
Modularity-based community detection |
| Label Propagation | algo.labelPropagation |
Fast community detection |
| WCC | algo.wcc |
Weakly connected components |
| SCC | algo.scc |
Strongly connected components |
| K-Core | algo.kCore |
K-core decomposition |
| Triangle Count | algo.triangleCount |
Count triangles per node |
// Louvain
CALL algo.louvain(['User'], ['INTERACTS'])
YIELD nodeId, communityId
// Label Propagation
CALL algo.labelPropagation(['User'], ['INTERACTS'])
YIELD nodeId, communityId
// Weakly Connected Components
CALL algo.wcc(['User'], ['INTERACTS'])
YIELD nodeId, componentId
// Strongly Connected Components
CALL algo.scc(['Task'], ['DEPENDS_ON'])
YIELD nodeId, componentId
// K-Core Decomposition
CALL algo.kCore(['User'], ['FRIEND'], 3)
YIELD nodeId, coreNumber
// Triangle Count
CALL algo.triangleCount(['User'], ['FRIEND'])
YIELD nodeId, triangleCount
Path Finding Algorithms¶
| Algorithm | Procedure | Description |
|---|---|---|
| Dijkstra | algo.dijkstra |
Shortest weighted path |
| Bellman-Ford | algo.bellmanFord |
Shortest path with negative weights |
| A* | algo.astar |
Heuristic shortest path |
| Bidirectional Dijkstra | algo.bidirectionalDijkstra |
Two-way shortest path |
| K-Shortest Paths | algo.kShortestPaths |
Multiple shortest paths |
| All Simple Paths | algo.allSimplePaths |
All paths between nodes |
| APSP | algo.allPairsShortestPath |
All pairs shortest path |
// Dijkstra shortest path
CALL algo.dijkstra(['Station'], ['CONNECTS'], $startId, $endId, 'distance')
YIELD path, cost
// K-Shortest Paths
CALL algo.kShortestPaths(['Station'], ['CONNECTS'], $startId, $endId, 5)
YIELD path, cost
// All Pairs Shortest Path
CALL algo.allPairsShortestPath(['Station'], ['CONNECTS'])
YIELD sourceNodeId, targetNodeId, distance
Similarity & Traversal Algorithms¶
| Algorithm | Procedure | Description |
|---|---|---|
| Node Similarity | algo.nodeSimilarity |
Jaccard similarity |
| Random Walk | algo.randomWalk |
Random graph traversal |
| Maximal Cliques | algo.maximalCliques |
Find all maximal cliques |
| Graph Coloring | algo.graphColoring |
Vertex coloring |
// Node Similarity (Jaccard)
CALL algo.nodeSimilarity(['Product'], ['PURCHASED'])
YIELD node1, node2, similarity
// Random Walk
CALL algo.randomWalk(['Page'], ['LINKS'], 10, 5)
YIELD path
Structural Analysis Algorithms¶
| Algorithm | Procedure | Description |
|---|---|---|
| Topological Sort | algo.topologicalSort |
DAG ordering |
| Cycle Detection | algo.cycleDetection |
Find cycles |
| Bipartite Check | algo.bipartiteCheck |
Test bipartiteness |
| Bridges | algo.bridges |
Find bridge edges |
| Articulation Points | algo.articulationPoints |
Find cut vertices |
| Elementary Circuits | algo.elementaryCircuits |
Find all simple cycles |
// Topological sort (for DAGs)
CALL algo.topologicalSort(['Task'], ['DEPENDS_ON'])
YIELD nodeId, order
// Find articulation points
CALL algo.articulationPoints(['Router'], ['CONNECTS'])
YIELD nodeId
Flow & Matching Algorithms¶
| Algorithm | Procedure | Description |
|---|---|---|
| Maximum Matching | algo.maxMatching |
Maximum cardinality matching |
| Minimum Spanning Tree | algo.mst |
MST using Prim/Kruskal |
| Dinic's Algorithm | algo.dinic |
Maximum flow |
| Ford-Fulkerson | algo.fordFulkerson |
Maximum flow |
// Minimum Spanning Tree
CALL algo.mst(['City'], ['ROAD'], 'distance')
YIELD edge, cost
// Maximum Matching
CALL algo.maxMatching(['Worker', 'Job'], ['CAN_DO'])
YIELD node1, node2
Schema DDL¶
Uni supports Data Definition Language (DDL) statements for managing schema.
Create Label (Vertex Type)¶
// Create a label with properties
CREATE LABEL Paper (
title STRING NOT NULL,
year INT32,
abstract STRING,
embedding VECTOR(768)
)
// Create label with default values
CREATE LABEL Author (
name STRING NOT NULL,
h_index INT32 DEFAULT 0,
active BOOLEAN DEFAULT true
)
Create Edge Type¶
// Create edge type with source/destination constraints
CREATE EDGE TYPE AUTHORED FROM Author TO Paper (
position INT32,
corresponding BOOLEAN DEFAULT false
)
// Edge type between multiple label types
CREATE EDGE TYPE COLLABORATES FROM Author TO Author (
papers_count INT32
)
Alter Schema¶
// Add a property to an existing label
ALTER LABEL Paper ADD abstract STRING
// Drop a property
ALTER LABEL Paper DROP deprecated_field
// Rename a property
ALTER LABEL Paper RENAME old_name TO new_name
Drop Schema Elements¶
// Drop a label (must have no vertices)
DROP LABEL TempLabel
// Drop an edge type
DROP EDGE TYPE OLD_RELATIONSHIP
Constraints¶
Define and manage data integrity constraints.
Create Constraints¶
// Unique constraint
CREATE CONSTRAINT paper_doi_unique
FOR (p:Paper) REQUIRE p.doi IS UNIQUE
// Existence constraint (property must be present)
CREATE CONSTRAINT author_name_exists
FOR (a:Author) REQUIRE a.name IS NOT NULL
// Check constraint (custom validation)
CREATE CONSTRAINT paper_year_valid
FOR (p:Paper) REQUIRE p.year >= 1900 AND p.year <= 2100
Show Constraints¶
Drop Constraints¶
Database Management¶
Administrative commands and procedures for database maintenance.
BACKUP¶
Create a backup of the database to a specified destination.
// Backup to local path
BACKUP TO './backups/backup_2026_01_17'
// Backup to S3
BACKUP TO 's3://my-bucket/backups/backup_2026_01_17'
// Backup with options
BACKUP TO './backups/full' WITH incremental = false, compress = true
VACUUM¶
Reclaim storage space by removing deleted data and compacting files.
// Perform vacuum operation
VACUUM
// Note: VACUUM may take time on large databases
// and temporarily increases I/O load
CHECKPOINT¶
Force a checkpoint to flush all pending writes to durable storage.
// Force checkpoint
CHECKPOINT
// Useful before taking external backups
// or when durability guarantee is needed immediately
Compaction¶
// Trigger storage compaction
CALL db.compact()
YIELD fragmentsCompacted, bytesReclaimed, duration
// Check compaction status
CALL db.compactionStatus()
YIELD status, progress, estimatedRemaining
Snapshots¶
// Create a named snapshot
CALL db.snapshot.create('before_migration')
YIELD name, created, size
// List available snapshots
CALL db.snapshot.list()
YIELD name, created, size
// Restore to a snapshot
CALL db.snapshot.restore('before_migration')
Schema Introspection¶
// List all labels
CALL db.labels()
YIELD label, propertyCount, nodeCount, indexCount
RETURN label, nodeCount
// List all relationship types
CALL db.relationshipTypes()
YIELD type, sourceLabels, targetLabels, propertyCount
RETURN type
// List all edge types (alias)
CALL db.edgeTypes()
YIELD type, sourceLabels, targetLabels, propertyCount
// List all indexes
CALL db.indexes()
YIELD name, type, label, properties, state
WHERE type = 'VECTOR'
RETURN name, label
// List all constraints
CALL db.constraints()
YIELD name, type, label, properties, enabled
RETURN name, type
// Get detailed label info
CALL db.schema.labelInfo('Paper')
YIELD property, dataType, nullable, indexed, unique
RETURN property, dataType
Schema DDL Procedures¶
Create and modify schema at runtime via procedures:
// Create a new label
CALL db.createLabel('Product', {
properties: {
name: { type: 'STRING', nullable: false },
price: { type: 'FLOAT64' },
embedding: { type: 'VECTOR', dimensions: 128 }
}
})
// Create an edge type
CALL db.createEdgeType('PURCHASED', ['Customer'], ['Product'], {
properties: {
quantity: { type: 'INT32' },
timestamp: { type: 'TIMESTAMP' }
}
})
// Create an index
CALL db.createIndex('Product', 'name', { type: 'BTREE' })
// Create a vector index
CALL db.createIndex('Product', 'embedding', {
type: 'VECTOR',
metric: 'cosine',
index_type: 'hnsw',
m: 16,
ef_construction: 200
})
// Create a constraint
CALL db.createConstraint('Product', 'UNIQUE', ['sku'])
// Drop operations
CALL db.dropLabel('TempLabel')
CALL db.dropEdgeType('OLD_RELATIONSHIP')
CALL db.dropIndex('Product', 'old_index')
CALL db.dropConstraint('Product', 'constraint_name')
CRDT Properties¶
Uni supports CRDT (Conflict-free Replicated Data Type) properties for distributed, eventually-consistent data. CRDT properties can be defined in the schema and manipulated via Cypher.
Schema Definition¶
Define CRDT properties in your schema:
{
"properties": {
"Paper": {
"title": { "type": "String", "nullable": false },
"view_count": { "type": "Crdt", "crdt_type": "GCounter" },
"tags": { "type": "Crdt", "crdt_type": "ORSet" },
"metadata": { "type": "Crdt", "crdt_type": "LWWMap" }
}
}
}
Supported CRDT Types¶
| Type | Description | Cypher Operations |
|---|---|---|
GCounter |
Grow-only counter | Increment only |
GSet |
Grow-only set | Add only |
ORSet |
Add/remove set (add-wins) | Add, remove |
LWWRegister |
Single value (last-writer-wins) | Set value |
LWWMap |
Key-value map (per-key LWW) | Put, remove keys |
Rga |
Ordered sequence | Insert, delete at position |
Querying CRDT Properties¶
// Read CRDT values (returns materialized value)
MATCH (p:Paper {id: 'paper_001'})
RETURN p.view_count, p.tags
// GCounter returns total count
// ORSet returns list of visible elements
// LWWMap returns map of non-tombstoned entries
Updating CRDT Properties¶
CRDT updates use special syntax to ensure conflict-free merging:
// Increment a GCounter
MATCH (p:Paper {id: 'paper_001'})
SET p.view_count = crdt.increment(p.view_count, 1)
// Add to an ORSet
MATCH (p:Paper {id: 'paper_001'})
SET p.tags = crdt.add(p.tags, 'machine-learning')
// Remove from an ORSet
MATCH (p:Paper {id: 'paper_001'})
SET p.tags = crdt.remove(p.tags, 'deprecated-tag')
// Update LWWMap
MATCH (p:Paper {id: 'paper_001'})
SET p.metadata = crdt.put(p.metadata, 'reviewed', true)
CRDT Functions¶
| Function | CRDT Types | Description |
|---|---|---|
crdt.increment(counter, n) |
GCounter | Increment by n |
crdt.add(set, elem) |
GSet, ORSet | Add element |
crdt.remove(set, elem) |
ORSet | Remove element |
crdt.set(register, value) |
LWWRegister | Set value |
crdt.put(map, key, value) |
LWWMap | Put key-value |
crdt.delete(map, key) |
LWWMap | Delete key |
crdt.insert(rga, index, elem) |
Rga | Insert at position |
crdt.deleteAt(rga, index) |
Rga | Delete at position |
Distributed Sync¶
CRDT properties enable conflict-free synchronization across distributed nodes:
┌─────────────┐ ┌─────────────┐
│ Node A │◄───────►│ Node B │
│ │ │ │
│ increment │ │ increment │
│ view_count │ │ view_count │
│ +5 │ │ +3 │
└──────┬──────┘ └──────┬──────┘
│ │
└───────────┬───────────┘
│
▼
┌─────────────┐
│ Merged │
│ view_count │
│ = 8 │
└─────────────┘
For detailed CRDT semantics and merge behavior, see CRDT Types.
Cypher Feature Status¶
| Feature | Status |
|---|---|
| MATCH (basic patterns) | Stable |
| WHERE (comparisons, boolean) | Stable |
| RETURN, ORDER BY, LIMIT, SKIP | Stable |
| Aggregations (COUNT, SUM, AVG, MIN, MAX, COLLECT) | Stable |
| Window Functions (OVER clause) | Stable |
| Scalar Functions (40+ functions) | Stable |
| CREATE (nodes and relationships) | Stable |
| WITH clause | Stable |
| UNWIND | Stable |
| CALL procedures | Stable |
| Index management | Stable |
| JSON Full-Text Search (CONTAINS) | Stable |
Variable-length paths (*1..3) |
Stable |
| MERGE | Stable |
| SET / REMOVE | Stable |
| DELETE / DETACH DELETE | Stable |
| UNION / UNION ALL | Stable |
| WITH RECURSIVE (CTEs) | Stable |
| EXPLAIN (with index usage) | Stable |
| PROFILE (runtime statistics) | Stable |
Session Variables ($session.*) |
Stable |
Temporal Queries (uni.validAt, VALID_AT) |
Stable |
| Schema DDL (CREATE/ALTER/DROP LABEL) | Stable |
Schema DDL Procedures (db.createLabel, etc.) |
Stable |
| Constraints (UNIQUE, EXISTS, CHECK) | Stable |
| Composite Key Constraints | Stable |
| Graph Algorithms (36 algorithms) | Stable |
| CRDT Properties | Stable |
| Database Management (BACKUP, VACUUM, CHECKPOINT) | Stable |
| Snapshots (create, list, restore) | Stable |
| Schema Introspection (db.labels, db.indexes, etc.) | Stable |
| Inverted Index (ANY IN pattern) | Stable |
| OPTIONAL MATCH | Planned |
| Subqueries | Planned |
Next Steps¶
- Vector Search — Semantic similarity queries
- Data Ingestion — Bulk import and streaming writes
- Performance Tuning — Query optimization strategies
- Troubleshooting — Common issues and solutions