# Query Engine **Last Updated:** 2026-02-01 **Confidence:** High **Status:** Implemented in `stemedb-query` v0.1.0 ## Summary The Query Engine provides lifecycle-aware filtering for reading assertions from the knowledge graph. **Key Facts:** - Filters by subject, predicate, lifecycle, epoch - **Fast path**: checks `MV:{subject}:{predicate}` for pre-computed winner (O(1)) - **MV staleness control**: `max_stale` parameter to reject stale materialized views - **Compound index**: `SP:{subject}:{predicate}` for subject+predicate lookups (O(1)) - **Subject index**: `S:{subject}` for subject-only lookups (O(1)) - Falls back to full scan when no index available **File Pointers:** - `crates/stemedb-query/src/engine.rs` - QueryEngine with fast-path and staleness check - `crates/stemedb-query/src/query.rs` - Query and QueryResult types ## Query Structure ```rust pub struct Query { pub subject: Option, pub predicate: Option, pub lifecycle: Option, pub epoch: Option, pub limit: Option, pub max_stale: Option, // Maximum MV age in seconds } ``` ## Usage ```rust let query = Query::builder() .subject("Tesla") .predicate("revenue") .lifecycle(LifecycleStage::Approved) .max_stale(300) // Only use MVs < 5 minutes old .limit(10) .build(); let result = engine.execute(&query).await?; ``` ## MV Staleness Control The `max_stale` parameter controls whether the fast path (materialized view) is used: | `max_stale` | Behavior | |-------------|----------| | `None` (default) | Accept any MV age (backward compatible) | | `Some(0)` | Only accept brand-new MVs (age = 0 seconds) | | `Some(60)` | Only use MV if materialized within last 60 seconds | | `Some(300)` | Only use MV if materialized within last 5 minutes | When the MV is stale, the query falls through to the slow path (SP index lookup + lens resolution). **Use cases:** - Real-time dashboards: `max_stale(60)` for fresh data - Audit investigations: `max_stale(0)` to ensure current state - Batch processing: `None` for maximum performance ## Query Execution Strategy 0. **Fast path** (subject + predicate): `MV:{subject}:{predicate}` → `MaterializedView.winner` (O(1)) - Skips if MV doesn't exist - Skips if MV is too stale (`max_stale` check) - Skips if winner doesn't match filters (lifecycle, epoch) 1. **Compound index** (subject + predicate): `SP:{subject}:{predicate}` → hashes (O(1)) 2. **Subject index** (subject only): `S:{subject}` → hashes (O(1)) 3. **Full scan** (no subject): Scan `H:` prefix (O(n)) 4. **Filter**: Apply lifecycle/epoch filters on candidates 5. **Limit**: Truncate if limit specified ## Related Topics - [Materializer](./materializer.md) - Produces the MV: keys used by fast path - [Assertion](./assertion.md) - [Lifecycle Stages](./lifecycle.md) - [Lens Resolution](./lens.md)