Cypher Query Language Reference
HyperMesh DB uses a Cypher-compatible query language extended for native
N-ary hyperedges. Every statement is passed to Connection.execute() or
the /v1/query REST endpoint.
MATCH — Read queries
Section titled “MATCH — Read queries”Temporal range query (TPI Bucket Pushdown)
Section titled “Temporal range query (TPI Bucket Pushdown)”MATCH HYPEREDGE (he:<Table>)WHERE he.event_ts >= <start> AND he.event_ts <= <end>RETURN *The query planner pushes the time range into the TPI (Temporal Property Index) and reads only the buckets that overlap the range. No full-table scan occurs. This is the primary read path for time-series workloads.
-- Example: all coalitions in the last 60 secondsMATCH HYPEREDGE (he:CoProximity)WHERE he.event_ts >= 940 AND he.event_ts <= 1000RETURN *Node membership query (FMI Lookup)
Section titled “Node membership query (FMI Lookup)”MATCH HYPEREDGE (he:<Table>) WHERE <node_id> IN he.members RETURN *The FMI (Forward Member Index) is a persistent inverted index. Membership lookup is O(log N) and returns all hyperedges that contain the given node.
-- All coalitions node 42 participated inMATCH HYPEREDGE (he:CoProximity) WHERE 42 IN he.members RETURN *Full table scan
Section titled “Full table scan”MATCH HYPEREDGE (he:<Table>) RETURN *Returns every record. Use with care on large tables.
Property filter predicates
Section titled “Property filter predicates”After a temporal range or membership scan, additional predicates filter in-memory results:
| Predicate | Meaning |
|---|---|
he.weight > 0.8 | Built-in float column — greater than |
he.weight >= 0.5 AND he.weight < 1.0 | Range on float |
he.formation = "V" | String equality |
he.<custom_col> = value | User-defined column (indexed via PSI) |
-- Temporal range + weight filterMATCH HYPEREDGE (he:Flights)WHERE he.event_ts >= 1000 AND he.event_ts <= 2000 AND he.weight > 0.9RETURN *Boolean predicates — OR, NOT, <>
Section titled “Boolean predicates — OR, NOT, <>”Single-pattern MATCH HYPEREDGE queries support boolean WHERE expressions
using AND, OR, NOT, parentheses, and the inequality operators <> / !=
(in addition to =, >, >=, <, <=):
MATCH HYPEREDGE (he:Sensors)WHERE he.label = 'alpha' AND (he.severity = 4 OR he.severity = 5)RETURN he.event_ts
MATCH HYPEREDGE (he:Sensors)WHERE NOT he.label = 'alpha' AND he.severity <> 1RETURN *Semantics & limits:
- Standard precedence:
NOTbinds tightest, thenAND, thenOR; use parentheses to group. - A comparison against a missing column or a
NULLvalue isfalse(soNOT he.x = 1keeps rows wherexis absent or≠ 1). - These boolean predicates are evaluated in the Python layer, so a query using
OR/NOT/<>performs a full table scan (TPI/PSI pushdown is not applied to disjunctive predicates). PureANDqueries keep index pushdown. - Supported for single-pattern
MATCH HYPEREDGEreads only. Joins andDELETE/UPDATEremainAND-only, andIN/memberspredicates cannot be combined withOR/NOT(a clear error is raised).
Built-in columns
Section titled “Built-in columns”Every hyperedge table exposes these columns:
| Column | Type | Description |
|---|---|---|
event_ts | uint32 | Event timestamp (seconds since epoch or mission start) |
members | uint32[] | Ordered member node IDs |
weight | float32 | Edge weight (default 0.0) |
mean_dist_m | float32 | Mean pairwise distance in metres (default 0.0) |
formation | string(16) | Formation label (default "") |
User-defined columns are added via ALTER TABLE … ADD COLUMN and appear
after the built-in columns in RETURN * results.
Projection, ordering & pagination
Section titled “Projection, ordering & pagination”RETURN queries support projection/aggregation, ORDER BY, and pagination
with LIMIT and SKIP / OFFSET (OFFSET is a synonym for SKIP). The
clauses are evaluated in standard order — ORDER BY → SKIP → LIMIT —
regardless of the order they appear textually, so the result is a stable page.
-- Rows 101–150 of the time-ordered result (page 3, page size 50)MATCH HYPEREDGE (he:Flights)WHERE he.event_ts >= 1000 AND he.event_ts <= 2000RETURN he.event_ts, he.weightORDER BY he.event_ts ASCSKIP 100 LIMIT 50SKIP / OFFSET also work without an explicit RETURN (like LIMIT) and
with parameter substitution (SKIP $offset). They
are applied over the materialised result set; to iterate very large ranges with
bounded memory, prefer hypermesh.scan_windows().
MATCH across multiple tables (Join)
Section titled “MATCH across multiple tables (Join)”MATCH HYPEREDGE (a:<Table1>), HYPEREDGE (b:<Table2>)WHERE a.event_ts >= T1 AND a.event_ts <= T2 AND b.event_ts >= T1 AND b.event_ts <= T2 AND <join-predicate>RETURN *Supported join predicates:
| Join type | Predicate syntax | Description |
|---|---|---|
| Temporal overlap | a.event_ts = b.event_ts | Both edges share the same timestamp |
| Member intersection | a.members = b.members | Both edges share a common member |
| Property equality | a.<col> = b.<col> | Any shared property value |
| Causal chain | a.event_ts < b.event_ts AND a.members = b.members | Member appears later |
-- Drones that were in CoProximity AND also had a CommLink eventMATCH HYPEREDGE (c:CoProximity), HYPEREDGE (l:CommLink)WHERE c.event_ts >= 100 AND c.event_ts <= 200 AND l.event_ts >= 100 AND l.event_ts <= 200 AND c.members = l.membersRETURN *Results are returned with alias-prefixed column names: c.event_ts,
c.members, l.event_ts, l.members, etc.
INSERT
Section titled “INSERT”INSERT INTO <Table> (event_ts, members [, col ...])VALUES (<ts>, [<m1>, <m2>, ...] [, <val> ...])Writes one hyperedge to the WAL. The record is immediately visible to all subsequent reads (WAL merging).
INSERT INTO CoProximity (event_ts, members, weight, formation)VALUES (1000, [1, 2, 3], 0.85, "delta")UPDATE
Section titled “UPDATE”UPDATE <Table> SET <col> = <val> [, <col> = <val> ...]WHERE event_ts = <ts> AND members = [<m1>, <m2>, ...]Semantics:
- UPDATE requires the compound key
(event_ts, members)in the WHERE clause to identify a specific hyperedge. There is no other primary key. - Internally, UPDATE issues a WAL DELETE tombstone for the old record then writes a new WAL INSERT with the modified fields.
- The updated record is not visible in MATCH queries until
compact()is called. This is by design: the WAL is sequential-append, so UPDATE is always safe to call, but visibility requires a compaction cycle. - If the WHERE clause matches zero records,
rows_affectedin the result will be0. Callers must check this value — no exception is raised.
-- Update weight for a specific hyperedgeUPDATE CoProximity SET weight = 0.95, formation = "V"WHERE event_ts = 1000 AND members = [1, 2, 3]Checking for successful update:
r = db.execute("UPDATE CoProximity SET weight = 0.95 WHERE event_ts = 1000 AND members = [1,2,3]")if r.rows[0]["rows_affected"] == 0: print("WARNING: no record matched the UPDATE predicate")db.compact(table="CoProximity") # make the change visibleDELETE
Section titled “DELETE”DELETE HYPEREDGE FROM <Table>WHERE event_ts = <ts> AND members = [<m1>, <m2>, ...]Writes a WAL tombstone. The record is hidden from subsequent reads immediately (WAL merge applies tombstones in real-time).
DELETE HYPEREDGE FROM CoProximityWHERE event_ts = 1000 AND members = [1, 2, 3]DDL — Data Definition Language
Section titled “DDL — Data Definition Language”Create / drop table
Section titled “Create / drop table”CREATE HYPEREDGE TABLE <name> (<MemberType> [, ...]) [BUCKET_SECONDS <n>] [COMPACT_THRESHOLD <n>]| Option | Default | Description |
|---|---|---|
BUCKET_SECONDS | 60 | TPI time-bucket width in seconds. Smaller = finer granularity, more buckets. |
COMPACT_THRESHOLD | 0 (off) | Auto-compact after N WAL entries. 0 = disabled. |
CREATE HYPEREDGE TABLE SwarmEvents (Drone) BUCKET_SECONDS 30 COMPACT_THRESHOLD 500DROP HYPEREDGE TABLE SwarmEventsSchema evolution
Section titled “Schema evolution”ALTER TABLE <t> ADD COLUMN <col> <type> [DEFAULT <value>]ALTER TABLE <t> DROP COLUMN <col>ALTER TABLE <t> RENAME TO <new_name>Supported column types: FLOAT, INT, STRING.
ALTER TABLE SwarmEvents ADD COLUMN altitude FLOAT DEFAULT 0.0ALTER TABLE SwarmEvents DROP COLUMN altitudeALTER TABLE SwarmEvents RENAME TO DroneEventsIndexes (Property Secondary Index — PSI)
Section titled “Indexes (Property Secondary Index — PSI)”CREATE INDEX ON <table> (<column>)DROP INDEX ON <table> (<column>)SHOW INDEXES [ON <table>]A PSI enables sub-linear property filtering on user-defined float or int
columns. Without an index, WHERE he.<col> = v is a full scan of in-memory
results; with an index it becomes a binary search.
CREATE INDEX ON CoProximity (altitude)Inspect tables
Section titled “Inspect tables”CALL SHOW_HYPEREDGE_TABLES() RETURN *Transactions
Section titled “Transactions”BEGIN [TRANSACTION]-- ... one or more INSERT / DELETE statements ...COMMIT [TRANSACTION]-- or:ROLLBACK [TRANSACTION]All INSERTs and DELETEs issued between BEGIN and COMMIT are buffered
in memory and applied atomically. If ROLLBACK is called, all buffered
writes are discarded and WAL tombstones are written for any inserts that
were already flushed.
Python context-manager shorthand:
with db.transaction(): db.execute("INSERT INTO T (event_ts, members) VALUES (100, [1,2])") db.execute("INSERT INTO T (event_ts, members) VALUES (101, [3,4])")# auto-commits on success, auto-rolls-back on exceptionQuery introspection
Section titled “Query introspection”EXPLAIN <query> -- returns query plan, no data rowsANALYZE <query> -- returns data rows AND query planThe query plan contains:
| Field | Description |
|---|---|
strategy | TPI_RANGE, FMI_LOOKUP, FULL_SCAN, or JOIN |
index_type | TPI, FMI, PSI, or NONE |
buckets_scanned | Number of TPI buckets read |
total_buckets | Total TPI buckets in the table |
estimated_rows | Estimated result count before filtering |
wal_entries_merged | WAL entries merged with the TPI result |
EXPLAIN MATCH HYPEREDGE (he:CoProximity)WHERE he.event_ts >= 100 AND he.event_ts <= 200RETURN *COPY FROM — Bulk ingestion
Section titled “COPY FROM — Bulk ingestion”COPY <Table> FROM '<path>' [(<options>)]Loads a CSV, Parquet, or JSON/NDJSON file into a table. The file is read on
the server filesystem; for client-side files use the Python SDK’s
copy_from_df() or copy_from_parquet().
| Option | Default | Description |
|---|---|---|
HEADER true/false | auto-detect | Whether the CSV has a header row |
DELIMITER ',' | , | CSV field separator |
IGNORE ERRORS | false | Skip malformed rows instead of raising |
COPY CoProximity FROM '/data/events.csv' (HEADER true, DELIMITER ',')COPY CoProximity FROM '/data/events.parquet'COPY CoProximity FROM '/data/events.ndjson' (IGNORE ERRORS)Parameter substitution
Section titled “Parameter substitution”Use $name placeholders in any query; pass a parameters dict to execute():
result = db.execute( "MATCH HYPEREDGE (he:T) WHERE he.event_ts >= $start AND he.event_ts <= $end RETURN *", parameters={"start": 1000, "end": 2000},)