Skip to content

Temporal Range Queries

HyperMesh DB’s primary query type is the temporal range query: retrieve all hyperedge records whose event_ts falls within a closed time interval [T, T+W].

Instead of scanning every record or traversing a B-tree, HyperMesh DB uses the TPI (Temporal Property Index) — a compact binary file partitioned into fixed-size time buckets.

TPI file layout:
┌─────────────────────────────────────────────────┐
│ File header (magic, version, bucket_seconds) │
├─────────────────────────────────────────────────┤
│ Bucket 0: [0, 10) → N₀ records │
│ Bucket 1: [10, 20) → N₁ records │
│ ... │
│ Bucket K: [K×10, (K+1)×10) → Nₖ records │
└─────────────────────────────────────────────────┘

A range query [T, T+W] computes:

first_bucket = T / bucket_seconds
last_bucket = (T + W) / bucket_seconds

Then calls pread() to read only buckets [first_bucket, last_bucket] — skipping all other buckets at O(1) cost.

MATCH HYPEREDGE (he:CoProximity)
WHERE he.event_ts >= 1000 AND he.event_ts <= 1030
RETURN *

Both bounds are optional. Omitting one turns it into a half-open range query.

result = db.execute("""
EXPLAIN
MATCH HYPEREDGE (he:CoProximity)
WHERE he.event_ts >= 1000 AND he.event_ts <= 1030
RETURN *
""")
print(result.rows[0])
# { strategy: "TPI_BUCKET_PUSHDOWN", buckets_scanned: 3,
# total_buckets: 100, speedup_factor: 33.3, elapsed_us: 42 }

Default bucket size is 10 seconds. Configure at table creation:

CREATE HYPEREDGE TABLE Events (Node) BUCKET_SECONDS 60

Smaller buckets → faster range queries (fewer records per bucket), larger index file.
Larger buckets → smaller index file, more records per read.

For a 30-second window over a 1000-second timeline with 10-second buckets: only 3 of 100 buckets are read — a 33× speedup over full scan.