Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
18 commits
Select commit Hold shift + click to select a range
bb20a8d
docs: describe continuous aggregate DDL with BUCKET and AGGREGATE cla…
farhan-syah Oct 13, 2026
1785d26
feat(timeseries): serve continuous aggregates as relations and route …
farhan-syah Oct 13, 2026
309a819
fix(kv): answer secondary index equality probes from complete coverage
farhan-syah Oct 13, 2026
b914135
feat(timeseries): merge the partitions of one interval into one
farhan-syah Oct 13, 2026
2029313
fix(crdt): install collection constraints before DDL returns
farhan-syah Oct 13, 2026
1439bbf
fix(pgwire): read prepared result columns under their executor key
farhan-syah Oct 13, 2026
9ba1c97
feat(sql): join derived tables and CTEs, and type their columns
farhan-syah Oct 13, 2026
6f59d65
fix: avoid panicking slices and untrusted preallocation in parsers
farhan-syah Oct 13, 2026
26605ef
fix(bootstrap): stop the core stall monitor judging short windows
farhan-syah Oct 13, 2026
764cc52
perf(surrogate): bind keys in batches with one durable sync
farhan-syah Oct 13, 2026
932a768
test(cluster): poll for applied entries in raft loop test
farhan-syah Oct 13, 2026
d9c3b60
fix(crdt): install constraints on the leader of the collection's group
farhan-syah Oct 13, 2026
bd5416b
fix(timeseries): run continuous aggregate refresh on the root's group
farhan-syah Oct 13, 2026
a05e4eb
fix(gateway): fill provider relation rows before dispatch
farhan-syah Oct 13, 2026
bc40c16
fix(auth-lease): give a lapsed lease a full renewal round of grace
farhan-syah Oct 14, 2026
0dc2c31
test(cluster): wait for authorization leases and bound hung steps
farhan-syah Oct 14, 2026
031fa1b
chore(deps): refresh lockfile and deny config
farhan-syah Oct 14, 2026
a1b95c2
perf(write): batch multi-row inserts and upserts into one request
farhan-syah Oct 14, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
23 changes: 13 additions & 10 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 6 additions & 0 deletions deny.toml
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,12 @@ ignore = [
"RUSTSEC-2026-0247", # bitmaps; review-by: 2027-05-01
"RUSTSEC-2026-0248", # im; review-by: 2027-05-01
"RUSTSEC-2026-0251", # sized-chunks; review-by: 2027-05-01
# lindera reads its tokenizer config through serde_yaml_ng, which pulls
# unsafe-libyaml. The crate was archived upstream with no fixed version
# and no known security impact. lindera parses YAML only from the config
# file the operator names in LINDERA_CONFIG_PATH, never client input.
# Revisit on each lindera upgrade.
"RUSTSEC-2024-0449", # unsafe-libyaml; review-by: 2027-05-01
]

[licenses]
Expand Down
25 changes: 10 additions & 15 deletions docs/ai/evaluation-tracking.md
Original file line number Diff line number Diff line change
Expand Up @@ -96,25 +96,20 @@ CREATE COLLECTION model_perf (
) WITH (engine='timeseries', partition_by='1h', retention='90d');

-- Continuous aggregation: 5-minute rollups for dashboards
CREATE CONTINUOUS AGGREGATE model_perf_5m
ON model_perf
AS
SELECT time_bucket('5 minutes', ts) AS bucket,
model_name,
endpoint,
AVG(latency_ms) AS avg_latency,
AVG(score) AS avg_score,
SUM(CASE WHEN error THEN 1 ELSE 0 END) AS error_count,
COUNT(*) AS request_count
FROM model_perf
GROUP BY bucket, model_name, endpoint;
CREATE CONTINUOUS AGGREGATE model_perf_5m ON model_perf
BUCKET '5m'
AGGREGATE avg(latency_ms) AS avg_latency,
avg(score) AS avg_score,
max(latency_ms) AS max_latency,
count(*) AS request_count
GROUP BY model_name, endpoint;

-- Dashboard query: latency trend for the last 24 hours
SELECT ts, model_name, avg_latency, avg_score, error_count, request_count
SELECT bucket, model_name, avg_latency, avg_score, max_latency, request_count
FROM model_perf_5m
WHERE model_name = 'retriever-v3'
AND ts > NOW() - INTERVAL '24 hours'
ORDER BY ts;
AND bucket > NOW() - INTERVAL '24 hours'
ORDER BY bucket;

-- Drift detection: compare this week's average to last week's
SELECT
Expand Down
35 changes: 24 additions & 11 deletions docs/query-language.md
Original file line number Diff line number Diff line change
Expand Up @@ -766,18 +766,14 @@ SHOW MATERIALIZED VIEWS;

### Continuous Aggregates

Continuous aggregates are incrementally maintained views over timeseries collections. Unlike `REFRESH MATERIALIZED VIEW` (full re-scan), continuous aggregates update only the new watermark window.
Continuous aggregates are incrementally maintained views over timeseries collections. Unlike `REFRESH MATERIALIZED VIEW` (full re-scan), continuous aggregates fold only new data into per-bucket state.

```sql
CREATE CONTINUOUS AGGREGATE cpu_hourly
ON cpu_metrics
AS
SELECT time_bucket('1 hour', ts) AS hour,
host,
AVG(cpu) AS avg_cpu
FROM cpu_metrics
GROUP BY hour, host
WITH (refresh_interval = '1m');
CREATE CONTINUOUS AGGREGATE cpu_hourly ON cpu_metrics
BUCKET '1h'
AGGREGATE avg(cpu) AS avg_cpu, count(*) AS samples
GROUP BY host
WITH (refresh_interval = '1m', retention = '365d');

-- Manually trigger a refresh
REFRESH CONTINUOUS AGGREGATE cpu_hourly;
Expand All @@ -787,6 +783,23 @@ SHOW CONTINUOUS AGGREGATES;
DROP CONTINUOUS AGGREGATE cpu_hourly;
```

`BUCKET` sets the bucket width. `AGGREGATE` functions: `count`, `sum`, `avg`, `min`, `max`, `first`, `last`, `count_distinct`, `approx_count_distinct`, `percentile(col, q)` (also `ts_percentile`, `approx_percentile`), `topk(col, k)` (also `approx_topk`). `GROUP BY` is optional.

`WITH` options:

| Option | Value |
| ------ | ----- |
| `refresh_policy` | `on_flush` (default), `on_seal`, `manual`, or an interval such as `'5m'` (folds periodically) |
| `refresh_interval` | Interval such as `'1m'`. Folds periodically on the maintenance tick. |
| `retention` | Interval after which the aggregate drops old buckets |

- `on_flush` and `on_seal` aggregates fold each flushed partition once.
- An interval `refresh_policy` or `refresh_interval` folds on the maintenance tick at that interval.
- `manual` aggregates fold only on `REFRESH CONTINUOUS AGGREGATE`. A read serves the last refresh.
- Aggregate state survives restart and keeps its history after raw retention removes the source rows.
- `SELECT * FROM cpu_hourly` returns one row per bucket and group: `bucket`, the `GROUP BY` columns, then the outputs.
- The aggregate is read-only.

## Engine-Specific SQL

### Vector Search
Expand Down Expand Up @@ -1257,7 +1270,7 @@ SHOW USERS;

`NOW()`, `CURRENT_TIMESTAMP()`, `EXTRACT(field FROM ts)`, `DATE_TRUNC(unit, ts)`, `DATE_FORMAT(ts, fmt)`, `time_bucket(interval, ts)`

`time_bucket(interval, ts)` — truncates `ts` to the nearest `interval` boundary. Registered as a DataFusion ScalarUDF. Accepts interval literals (`'5m'`, `'1h'`, `'1d'`) and ISO 8601 durations (`'PT5M'`, `'PT1H'`). Used in timeseries aggregations and continuous aggregate definitions.
`time_bucket(interval, ts)` — truncates `ts` to the nearest `interval` boundary. Registered as a DataFusion ScalarUDF. Accepts interval literals (`'5m'`, `'1h'`, `'1d'`) and ISO 8601 durations (`'PT5M'`, `'PT1H'`). Used in timeseries aggregations. Continuous aggregate definitions do not use it. They set the bucket with `BUCKET`.

### Type

Expand Down
46 changes: 31 additions & 15 deletions docs/timeseries.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ Timeseries is a **columnar profile**. It extends the [Columnar engine](columnar.

- **Cascading compression** — ALP + FastLanes + FSST + Pcodec + rANS + LZ4. Achieves 20-40x compression on typical telemetry, compared to 3-5x from single-pass approaches.
- **ILP ingest** — InfluxDB Line Protocol for high-throughput metric ingestion with adaptive batching and per-series core routing.
- **Continuous aggregation** — Incrementally maintained materialized views with watermarks, multi-tier chaining, and out-of-order handling. No full re-scan on refresh.
- **Continuous aggregation** — Incrementally maintained per-bucket state, folded from flushed partitions. No full re-scan on refresh.
- **Retention policies** — Automatic expiry of old data by time partition.
- **Approximate aggregation** — HyperLogLog (cardinality), t-digest (percentiles), SpaceSaving (top-K), Count-Min Sketch (frequency). All mergeable across shards and usable in continuous aggregation.
- **Block-level skip** — Sparse primary index with min/max statistics per block. Queries skip irrelevant time ranges without decompression.
Expand Down Expand Up @@ -53,11 +53,10 @@ GROUP BY bucket, host
ORDER BY bucket DESC;

-- Continuous aggregation (incremental, no full re-scan)
CREATE CONTINUOUS AGGREGATE cpu_hourly
ON cpu_metrics
BUCKET '1 hour'
AGGREGATE AVG(cpu_usage) AS avg_cpu, ts_percentile(cpu_usage, 0.99) AS p99_cpu
GROUP BY time_bucket('1 hour', ts) AS hour, host
CREATE CONTINUOUS AGGREGATE cpu_hourly ON cpu_metrics
BUCKET '1h'
AGGREGATE avg(cpu_usage) AS avg_cpu, ts_percentile(cpu_usage, 0.99) AS p99_cpu
GROUP BY host
WITH (refresh_interval = '1m');

-- Approximate aggregation
Expand Down Expand Up @@ -107,16 +106,15 @@ GROUP BY bucket;

## Continuous Aggregation DDL

Continuous aggregates are incrementally maintained views over a timeseries collection. They refresh automatically as new data arrives — no full re-scan on each refresh.
A continuous aggregate folds new rows of a timeseries collection into per-bucket state. It never re-scans the source.

```sql
-- Create a continuous aggregate
CREATE CONTINUOUS AGGREGATE cpu_hourly
ON cpu_metrics
BUCKET '1 hour'
AGGREGATE AVG(cpu_usage) AS avg_cpu, ts_percentile(cpu_usage, 0.99) AS p99_cpu
GROUP BY time_bucket('1 hour', ts) AS hour, host
WITH (refresh_interval = '1m');
CREATE CONTINUOUS AGGREGATE cpu_hourly ON cpu_metrics
BUCKET '1h'
AGGREGATE avg(cpu_usage) AS avg_cpu, ts_percentile(cpu_usage, 0.99) AS p99_cpu
GROUP BY host
WITH (refresh_interval = '1m', retention = '365d');

-- Manually trigger a refresh
REFRESH CONTINUOUS AGGREGATE cpu_hourly;
Expand All @@ -128,7 +126,25 @@ SHOW CONTINUOUS AGGREGATES;
DROP CONTINUOUS AGGREGATE cpu_hourly;
```

The `refresh_interval` controls how often the engine checks for new data since the last watermark. Out-of-order data within the watermark window is handled automatically.
`BUCKET` sets the bucket width. Do not use `time_bucket(...)` in the definition.

| Clause | Meaning |
| ------ | ------- |
| `AGGREGATE f(col) [AS alias], ...` | Outputs. Functions: `count`, `sum`, `avg`, `min`, `max`, `first`, `last`, `count_distinct`, `approx_count_distinct`, `percentile(col, q)` (also `ts_percentile`, `approx_percentile`), `topk(col, k)` (also `approx_topk`). `q` is in `[0, 1]`. `k` is at least 1. Use `count(*)` to count rows. |
| `GROUP BY col, ...` | Optional. Adds group columns to each bucket. |
| `refresh_policy` | `on_flush` (default), `on_seal`, `manual`, or an interval such as `'5m'` (folds periodically). |
| `refresh_interval` | Interval such as `'1m'`. Folds periodically on the maintenance tick. |
| `retention` | Interval after which the aggregate drops old buckets. |

Refresh behavior:

- `on_flush` and `on_seal` aggregates fold each flushed partition once.
- `refresh_interval` makes the aggregate periodic. It folds on the maintenance tick at that interval.
- `manual` aggregates fold only on `REFRESH CONTINUOUS AGGREGATE`. A read serves the last refresh.

Aggregate state survives restart. It keeps its history after raw retention removes the source rows.

`SELECT * FROM cpu_hourly` returns one row per bucket and group. Columns are `bucket`, the `GROUP BY` columns, then the outputs. The aggregate is read-only.

Continuous aggregate refreshes can also be triggered from the cron scheduler:

Expand All @@ -140,7 +156,7 @@ AS BEGIN
END;
```

This is useful when you want deterministic refresh timing rather than relying on the `refresh_interval` background timer. See [Real-Time Features](real-time.md#cron-scheduler) for the full cron scheduler reference.
This is useful when you want deterministic refresh timing rather than relying on the `refresh_interval` maintenance tick or the flush-time fold. See [Real-Time Features](real-time.md#cron-scheduler) for the full cron scheduler reference.

## ILP Ingest (InfluxDB Line Protocol)

Expand Down
4 changes: 2 additions & 2 deletions docs/vectors.md
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,7 @@ CREATE COLLECTION corpus (
tenant_id UUID,
created_at TIMESTAMP DEFAULT now()
) WITH (
primary='vector',
engine='vector',
vector_field='embedding',
dim=384,
metric='cosine',
Expand All @@ -125,7 +125,7 @@ CREATE COLLECTION corpus (
);
```

`primary='vector'` is purely an access-path hint — not a different engine. Cross-engine queries, CRDT sync, SQL semantics all keep working. `payload_indexes` are per-field equality / range / boolean indexes over the metadata sidecar for filtered ANN (replaces Pinecone metadata filters).
`engine='vector'` implies `primary='vector'`. It requires `vector_field` and `dim`; a missing one, or a contradicting `primary`, is refused with SQLSTATE `42601`. A document collection searched through a vector index uses `engine='document_schemaless'`. Cross-engine queries, CRDT sync, SQL semantics all keep working. `payload_indexes` are per-field equality / range / boolean indexes over the metadata sidecar for filtered ANN (replaces Pinecone metadata filters).

`storage_dtype` controls the precision of raw HNSW vector storage (independent of quantization). Accepted values: `F32` (default, 4 bytes/dimension), `F16` (2 bytes/dimension, IEEE half), `BF16` (2 bytes/dimension, bfloat16 — same exponent range as F32, better dynamic range for embeddings, preferred). Using `BF16` or `F16` halves resident vector bytes, reducing memory pressure on large indexes with a small accuracy cost. The HNSW graph structure and search quality remain unaffected.

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -191,7 +191,7 @@ async fn vector_search_restricts_allowed_ids_on_a_declared_key() {
&remote,
"CREATE COLLECTION sku_vecs \
FIELDS (sku TEXT PRIMARY KEY, embedding VECTOR(2)) \
WITH (engine='vector', m=8, ef_construction=50)",
WITH (engine='document_schemaless', m=8, ef_construction=50)",
)
.await;
for (sku, x) in [
Expand Down
Loading
Loading