Timelaketimelake
DocsBenchmarksRoadmapSpecContribute
Apache 2.0 ·
Roadmap

DoneIn progressPlanned

Tables and storage

Done:1. Iceberg tablesDone:2. CommitsDone:3. Object-store catalogIn progress:4. Time-series table contractIn progress:5. File layout and encodingsIn progress:6. Last-value indexDone:7. One-request table state and version checksDone:8. Table format versions and upgradesDone:9. SettingsPlanned:10. Supplemental timestamps

Writing

Done:11. AppendsDone:12. Late data and dedup on readDone:13. Writes from WebAssemblyPlanned:14. Hot tier and seconds-fresh readsPlanned:15. BackfillIn progress:16. Import and migrationPlanned:17. DeletesPlanned:18. GDPR erasure

Maintenance

Done:19. CompactionIn progress:20. Maintenance runs, retention and expiry

Reading

In progress:21. Timelake readerDone:22. Block cacheDone:23. Filter pushdownDone:24. Pruning with long IN listsDone:25. Newest-first scansDone:26. Scans in series orderDone:27. Materialized rollups

SQL functions

In progress:28. Function libraryDone:29. Time buckets and gap fillingDone:30. Signal aggregatesDone:31. Downsampling with m4

Integrations

Planned:32. REST catalogPlanned:33. DuckDB extensionPlanned:34. Snowflake connectionPlanned:35. Multitenancy

Services

Planned:36. Ingestion and rulesPlanned:37. Data to eventsPlanned:38. Static read modelsPlanned:39. Computed metricsPlanned:40. Agent access with permission setsPlanned:41. Device syncPlanned:42. Edge gatewayPlanned:43. Server mode

Benchmarks

In progress:44. Benchmark harness: timebenchIn progress:45. Industrial IoT benchmarkPlanned:46. Agent benchmark

Background

ArchitectureDeployment and cost modelEmbedded engine: DataFusionLandscape and positioningLicense and open corePurpose and requirementsReleases
TimelaketimelakeThe open time-series lakehouse.
v0 · Apache 2.0 · Contribute · GitHubBuilt on Apache Arrow, Apache DataFusion, Apache Parquet, and Apache Iceberg.
DocsBenchmarksRoadmapSpecContribute

Spec 30 · SQL functions

Signal aggregates

DoneUpdated 2026-10-19View on GitHub
Versions
0.7.0, unreleased
Roadmap
Time-series SQL
Related
26. Scans in series order, 27. Materialized rollups, 28. Function library, 31. Downsampling with m4

Summary

time_weighted_mean, integral, counter_diff and counter_rate over irregular readings, exact, as fast as avg. They share one mergeable state (runs of readings), which rollups store and several aggregates of one column compute once; a condition counts as 1 while true, for time in a state and uptime. gap_count and gap_seconds, how often and how long readings stopped, are run aggregates of the same kind.

Design

time_weighted_mean(time, value [, method]) and integral(time, value [, method]) (value × seconds), method forward_fill (default, alias ffill) or linear; counter_diff(time, value) and counter_rate(time, value) (per second), where a drop is a reset to zero, so the reading after it counts whole. All over each group's first to last reading; readings at one time count once with the largest value; one reading time gives its value as the mean, 0 as the integral and growth, and no rate. Decided with the user on 2026-10-18 (exact always, both methods, first to last reading).

  • State: a list of segments, runs of a group's readings in time order: first and last reading, the values of the readings next to them, the time from the first to the next and into the last, the area and the counter's growth. Segments that follow each other join exactly (the gap's area and growth added; a shared time takes the larger value, corrected through the stored neighbours); partial results emit their runs unjoined, since another partition may hold readings between them. Overlapping segments are an error. The four aggregates share the state and differ in what they return from it. Layout measured on IIoT hourly means: neighbours as Option<f64> (96-byte segments) 2.30 s, as plain f64s (80 bytes) 2.17 s, the same as the mean alone before; the open segment kept inline in each group instead of behind the vector's pointer 2.95 s (the group array doubles and DataFusion moves it as it grows).

  • Series order: no partition may have readings of a series inside another partition's run of it. Scans under a signal aggregate read each series whole and in time order, merging only the files that need it (spec 26, setting series-order).

  • Rollups store the state (time_weighted_state); routing merges it with the query's aggregate (integral(state [, method])), at the rollup's width too. One stored state answers all four for its column and method; the counters from either method's state.

  • Cost: IIoT small, hourly per tag over 30 days: avg 1.98 s; each signal aggregate 2.18–2.20 s; all four in one query 3.47 s with a state each, 2.11 s sharing one: an optimizer rule after routing replaces the signal aggregates of the same readings and method (the counters join either method's) with one time_weighted_state and computes each result from it in a projection (integral_of_state(state)); setting shared-signal-state. Against the window form of the IIoT queries over 30 days: energy per machine (lag) 1.66 → 1.09 s, time-weighted means of a line's temperatures (lead) 166 → 87 ms.

  • Gaps (built 2026-10-19, #123): gap_count(time, threshold) and gap_seconds(time, threshold), how many times and for how long in all a group's readings stopped for longer than threshold (an interval literal without months). A gap is the time from a reading to the next; silences before the first reading or after the last aren't gaps. Their run is a reading time's first and last, the gaps so far and their length (32 bytes, a run of its own rather than fields added to the signal segment, which cost 6% before); gap_state returns the state. The run code is generic (query/runs.rs: a Run trait, the runs of a group and the accumulators), shared with the signal aggregates at no cost (hourly means 3.58 → 3.50 s, all four 4.80 → 4.68 s, interleaved runs on a loaded machine). IIoT gaps of 100 one-second tags, same answers as the benchmark's lead() window form: a day 226 → 77 ms, 30 days 17.8 → 1.36 s. Rollups store the gap state (spec 27): from an hourly rollup, 30 days of gaps in 44 ms.

Open questions and issues

None open.

History

  • 2026-10-18: time_weighted_mean built
  • 2026-10-19: integral, counter_diff, counter_rate, conditions, shared state, scans in stretches of time
  • 2026-10-19: moved from SPEC.md into its own spec.
  • 2026-10-19: was spec 22; specs regrouped one per feature, with milestones on the roadmap.
  • 2026-10-19: gap_count and gap_seconds, on run code shared with the signal aggregates.