Skip to content

signalsLatest/lastSeen via signal_latest projection#284

Merged
elffjs merged 4 commits into
mainfrom
feat/signals-latest-projection
Apr 23, 2026
Merged

signalsLatest/lastSeen via signal_latest projection#284
elffjs merged 4 commits into
mainfrom
feat/signals-latest-projection

Conversation

@zer0stars

Copy link
Copy Markdown
Member

Summary

  • Rewrites getLatestQuery so the aggregate shapes match the signal_latest_by_subject_source_name projection added in DIMO-Network/model-garage#257 — non-location signals use argMax + max(timestamp), location signals use argMaxIf + maxIf with the same non-(0, 0) filter the projection carries, mixed queries UNION ALL the two branches.
  • Drops DEFAULT_LOOKBACK / Service.lookbackFrom and the timestamp WHERE clause on both getLatestQuery and getLastSeenQuery. The timestamp filter prevents projection matching, and the projection makes the lookback unnecessary — queries now read a handful of pre-aggregated rows per (subject, source, name) regardless of history depth.

Why

signalsLatest / lastSeen previously needed a 60-day lookback to keep scans bounded. Vehicles that hadn't reported in the last 60 days returned empty from signalsLatest. The projection stores one pre-aggregated row per (subject, source, name), so the lookback is no longer load-bearing and the full history is cheap to query.

Verification

ClickHouse 25.3 (podman), 20M-row ReplacingMergeTree signal table, 200 subjects, 8 partitions, with the new projection materialized:

Query system.query_log.projections match Rows read
non-location latest (speed, isIgnitionOn) 99.5k
location latest (argMaxIf + maxIf non-(0,0)) 99.5k
UNION ALL mixed + source filter 199k (both branches)
lastSeen (max(timestamp)) 99.5k

Results byte-identical between projection and force-base runs (SETTINGS optimize_use_projections = 0).

Deploy order

Must deploy only after DIMO-Network/model-garage#257 is materialized in the target environment. Without the projection, the now-unbounded queries will do full-history scans — regression vs today's 60-day lookback. Hold the deploy until system.mutations shows the MATERIALIZE PROJECTION mutation is done on signal and event.

Removed config

  • DEFAULT_LOOKBACK env var (was 60 in both values.yaml and values-prod.yaml)
  • DefaultLookbackDays field in config.Settings
  • Service.defaultLookback field, Service.lookbackFrom(), defaultLookbackDays const
  • Comment block in settings.sample.yaml

Test plan

  • go test ./... passes (unit + e2e testcontainers)
  • Live projection-match verification against ClickHouse 25.3 for every query shape the new code emits
  • Dev deploy after model-garage#257 is materialized in dev; confirm system.query_log.projections on live traffic shows the projection being hit
  • Prod deploy after materialization in prod; monitor signalsLatest p99
  • Spot-check a quiet vehicle (no reports in 60+ days) now returns data via signalsLatest

zer0stars and others added 4 commits April 17, 2026 16:28
Rewrites getLatestQuery to emit aggregate shapes that ClickHouse's
projection matcher picks up against the signal_latest_by_subject_source_name
projection added in model-garage. Non-location signals use
argMax + max(timestamp); location signals use argMaxIf + maxIf with the
same non-(0, 0) filter the projection carries. Mixed queries UNION ALL
the two shapes so each branch matches cleanly.

Drops DEFAULT_LOOKBACK / Service.lookbackFrom and the timestamp WHERE
clause on both getLatestQuery and getLastSeenQuery. The timestamp filter
prevents projection matching, and the projection itself makes the
lookback unnecessary -- queries now read a handful of pre-aggregated
rows per (subject, source, name) regardless of history depth.

Verified on ClickHouse 25.3 with a 20M-row ReplacingMergeTree signal
table: all four query shapes (non-location latest, location latest,
mixed UNION ALL with source filter, lastSeen) match the projection via
system.query_log.projections, and results are byte-identical to
force-base (optimize_use_projections=0) runs.

Must deploy only after DIMO-Network/model-garage#257 is materialized in
the target environment; otherwise these queries fall back to
full-history scans.
Fix up weird topK test
@elffjs
elffjs merged commit c21432e into main Apr 23, 2026
4 checks passed
@elffjs
elffjs deleted the feat/signals-latest-projection branch April 23, 2026 12:33
zer0stars added a commit that referenced this pull request Jun 11, 2026
* perf(ch): serve lastSeen query from signal_latest projection

The lastSeen UNION ALL branch aggregated max(timestamp) with no GROUP
BY, which the prod projection matcher does not serve -- every
signalsLatest/signalsSnapshot selecting lastSeen scanned the subject's
full signal history (p50 ~2900ms vs ~380ms for the name-filtered
branches, worse for high-history vehicles).

Wrap the aggregate so the inner query groups by name at the
signal_latest_by_subject_source_name projection grain; the outer query
re-aggregates to a single row. Result shape and semantics unchanged.

Refs #284

* build: pin golangci-lint and its installer to v2.12.1

master install.sh currently downloads the .sbom.json asset in place of
the tarball, so checksum verification fails for every version and CI
breaks on install-tools. Fetch install.sh from the release tag and pin
the version instead of tracking latest/master.
zer0stars added a commit that referenced this pull request Jun 11, 2026
…les (#298)

* chore: bump model-garage for signal_latest + summary table migrations

Pinned to the feat/signal-latest-table branch head (pre-v1.0.13
pseudo-version); re-pin to the v1.0.13 tag once released.

* perf(ch): serve latest-state and summary queries from precomputed tables

signalsLatest/signalsSnapshot/lastSeen/availableSignals now read the
precomputed signal_latest table (model-garage 00010) instead of
fanning out across every part of the raw signal table. Location
fields read kind=1 rows, which pre-filter (0,0) fixes, so plain
argMax replaces argMaxIf. Supersedes the projection-matching shapes
from #284/#297.

dataSummary per-name count/first-seen/last-seen now read the
AggregatingMergeTree summary tables (model-garage 00011) instead of
aggregating the raw tables. Counts are over raw inserts, matching the
approximation of the previous non-FINAL count(*) reads.

* style(ch): alias latest location column value_location for UNION consistency

Scanning is positional so agg_location worked, but the non-location
branch of the latest UNION ALL aliases its zero tuple value_location;
matching aliases keep the result shape self-describing.

* chore: pin model-garage to v1.0.13 release tag
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants