Chapter 12 · Time Series and Geospatial Workloads
Aggregations, Downsampling, Compaction Rules, and Multi-Series Queries
Turn raw AtlasMart telemetry into bounded time buckets and derived series while keeping bucket alignment, compaction state, labels, and multi-series aggregation observable.
Learning outcomes
AtlasMart’s raw temperature streams are useful for incident investigation, but dashboards and capacity planning need one-minute summaries across many sensors. The challenge is to reduce data volume without erasing bucket semantics or turning derived data into fake source truth.
Explain bucket duration, alignment, reported bucket timestamp, and partial latest-bucket semantics.
Run TS.RANGE aggregation separately from persisted compaction rules.
Create source→destination compaction rules and prove when a bucket becomes materialized.
Query many series with label filters and GROUPBY/REDUCE while bounding reply size.
Treat derived series as rebuildable state and measure memory/query cost before scaling.
All Chapter 12 mandatory labs reuse the disposable Chapter 01
environment: Redis Open Source 8.10.1 from Docker
Official Image redis:8.10.1, container
atlasmart-redis-ch01, standalone topology, host
publication 127.0.0.1:6379, TLS disabled only
because traffic stays on loopback, default ACL user disabled,
named users atlasmart-app and
academy-admin, logical database 0, AOF with
appendfsync everysec plus RDB snapshots,
persistent /data, and no explicit
maxmemory limit or eviction policy. Redis 8
integrates Time Series into Redis Open Source; geospatial
commands are core Redis commands. Fixtures stay under
atlasmart:ch12:*. Mandatory work is local and
uses synthetic telemetry/coordinates only; no paid service,
production endpoint, or real credential is required.
1. Aggregation answers a different question than raw range reads
A raw sample says “sensor s01 reported 4.2 at timestamp t.” A
bucket aggregate says “for this defined interval, the selected
reducer produced a summary.” Those statements have different
lineage. avg, max, sum,
count, and time-weighted average (twa)
are reducers, not storage formats.
| Layer | Question | Authoritative for |
|---|---|---|
| Raw series | What samples were ingested? | Ingested measurement history within retention |
| On-demand TS.RANGE aggregation | What is the aggregate for this query definition? | The query result at that time |
| Compaction destination | What derived buckets were materialized by the rule? | Rebuildable summary state |
| Application aggregate | What business metric combines Redis and non-Redis context? | The application-defined result |
2. Build deterministic raw series with bounded labels
docker exec -e REDISCLI_AUTH=AtlasMart-App-Lab-Only-2026 atlasmart-redis-ch01 redis-cli --user atlasmart-app TS.CREATE atlasmart:ch12:raw:temp:baku-01:s01 RETENTION 3600000 DUPLICATE_POLICY BLOCK LABELS tenant atlasmart site baku-01 zone cold-a metric temperature sensor s01 unit Cdocker exec -e REDISCLI_AUTH=AtlasMart-App-Lab-Only-2026 atlasmart-redis-ch01 redis-cli --user atlasmart-app TS.CREATE atlasmart:ch12:raw:temp:baku-01:s02 RETENTION 3600000 DUPLICATE_POLICY BLOCK LABELS tenant atlasmart site baku-01 zone cold-a metric temperature sensor s02 unit Cdocker exec -e REDISCLI_AUTH=AtlasMart-App-Lab-Only-2026 atlasmart-redis-ch01 redis-cli --user atlasmart-app TS.MADD atlasmart:ch12:raw:temp:baku-01:s01 0 4 atlasmart:ch12:raw:temp:baku-01:s01 20000 6 atlasmart:ch12:raw:temp:baku-01:s01 40000 8 atlasmart:ch12:raw:temp:baku-01:s01 60000 10 atlasmart:ch12:raw:temp:baku-01:s01 80000 12 atlasmart:ch12:raw:temp:baku-01:s02 0 5 atlasmart:ch12:raw:temp:baku-01:s02 20000 7 atlasmart:ch12:raw:temp:baku-01:s02 40000 9 atlasmart:ch12:raw:temp:baku-01:s02 60000 11 atlasmart:ch12:raw:temp:baku-01:s02 80000 13docker exec -e REDISCLI_AUTH=AtlasMart-App-Lab-Only-2026 atlasmart-redis-ch01 redis-cli --user atlasmart-app TS.INFO atlasmart:ch12:raw:temp:baku-01:s01
Using timestamps that fall exactly around 60,000-ms boundaries makes bucket behavior auditable by eye.
3. On-demand aggregation: bucket duration and alignment are part of the result
With no ALIGN, bucket boundaries are aligned to
multiples of the bucket duration from reference timestamp zero.
Changing alignment changes which raw samples share a bucket even
when the source data is identical.
docker exec -e REDISCLI_AUTH=AtlasMart-App-Lab-Only-2026 atlasmart-redis-ch01 redis-cli --user atlasmart-app TS.RANGE atlasmart:ch12:raw:temp:baku-01:s01 0 120000docker exec -e REDISCLI_AUTH=AtlasMart-App-Lab-Only-2026 atlasmart-redis-ch01 redis-cli --user atlasmart-app TS.RANGE atlasmart:ch12:raw:temp:baku-01:s01 0 120000 AGGREGATION avg 60000docker exec -e REDISCLI_AUTH=AtlasMart-App-Lab-Only-2026 atlasmart-redis-ch01 redis-cli --user atlasmart-app TS.RANGE atlasmart:ch12:raw:temp:baku-01:s01 10000 120000 ALIGN 10000 AGGREGATION avg 60000docker exec -e REDISCLI_AUTH=AtlasMart-App-Lab-Only-2026 atlasmart-redis-ch01 redis-cli --user atlasmart-app TS.RANGE atlasmart:ch12:raw:temp:baku-01:s01 0 120000 AGGREGATION min,avg,max 60000
Expected first aligned bucket for s01 at [0,60000) uses values
4, 6, and 8; the sample at 60000 belongs to the next bucket. The
min,avg,max multi-aggregator syntax is available in
current Redis Time Series; older client wrappers may lag even
when the server supports it.
4. Bucket timestamps can report start, midpoint, or end
docker exec -e REDISCLI_AUTH=AtlasMart-App-Lab-Only-2026 atlasmart-redis-ch01 redis-cli --user atlasmart-app TS.RANGE atlasmart:ch12:raw:temp:baku-01:s01 0 120000 AGGREGATION avg 60000 BUCKETTIMESTAMP startdocker exec -e REDISCLI_AUTH=AtlasMart-App-Lab-Only-2026 atlasmart-redis-ch01 redis-cli --user atlasmart-app TS.RANGE atlasmart:ch12:raw:temp:baku-01:s01 0 120000 AGGREGATION avg 60000 BUCKETTIMESTAMP middocker exec -e REDISCLI_AUTH=AtlasMart-App-Lab-Only-2026 atlasmart-redis-ch01 redis-cli --user atlasmart-app TS.RANGE atlasmart:ch12:raw:temp:baku-01:s01 0 120000 AGGREGATION avg 60000 BUCKETTIMESTAMP end
A dashboard that labels bucket timestamps inconsistently can appear shifted even when the aggregate values are identical. Record the bucket timestamp convention as part of the metric contract.
5. Create a persistent compaction rule and observe bucket closure
A compaction rule writes a derived destination series as source buckets close. The destination must be treated as derived state with its own retention plan. Create the rule before inserting the demonstration samples so the lab never implies that rule creation backfills older source history.
docker exec -e REDISCLI_AUTH=AtlasMart-App-Lab-Only-2026 atlasmart-redis-ch01 redis-cli --user atlasmart-app TS.CREATE atlasmart:ch12:raw:rule-demo:temp:baku-01:s01 RETENTION 3600000 DUPLICATE_POLICY BLOCK LABELS tenant atlasmart site baku-01 zone cold-a metric temperature sensor s01-demo unit Cdocker exec -e REDISCLI_AUTH=AtlasMart-App-Lab-Only-2026 atlasmart-redis-ch01 redis-cli --user atlasmart-app TS.CREATE atlasmart:ch12:rollup:rule-demo:temp:baku-01:s01:1m RETENTION 86400000 DUPLICATE_POLICY BLOCK LABELS tenant atlasmart site baku-01 zone cold-a metric temperature_1m source s01-demo unit C derived yesdocker exec -e REDISCLI_AUTH=AtlasMart-App-Lab-Only-2026 atlasmart-redis-ch01 redis-cli --user atlasmart-app TS.CREATERULE atlasmart:ch12:raw:rule-demo:temp:baku-01:s01 atlasmart:ch12:rollup:rule-demo:temp:baku-01:s01:1m AGGREGATION avg 60000 0docker exec -e REDISCLI_AUTH=AtlasMart-App-Lab-Only-2026 atlasmart-redis-ch01 redis-cli --user atlasmart-app TS.MADD atlasmart:ch12:raw:rule-demo:temp:baku-01:s01 0 4 atlasmart:ch12:raw:rule-demo:temp:baku-01:s01 20000 6 atlasmart:ch12:raw:rule-demo:temp:baku-01:s01 40000 8 atlasmart:ch12:raw:rule-demo:temp:baku-01:s01 60000 10 atlasmart:ch12:raw:rule-demo:temp:baku-01:s01 80000 12docker exec -e REDISCLI_AUTH=AtlasMart-App-Lab-Only-2026 atlasmart-redis-ch01 redis-cli --user atlasmart-app TS.INFO atlasmart:ch12:raw:rule-demo:temp:baku-01:s01docker exec -e REDISCLI_AUTH=AtlasMart-App-Lab-Only-2026 atlasmart-redis-ch01 redis-cli --user atlasmart-app TS.INFO atlasmart:ch12:rollup:rule-demo:temp:baku-01:s01:1mdocker exec -e REDISCLI_AUTH=AtlasMart-App-Lab-Only-2026 atlasmart-redis-ch01 redis-cli --user atlasmart-app TS.RANGE atlasmart:ch12:rollup:rule-demo:temp:baku-01:s01:1m - +
A compaction bucket is normally finalized when a later sample
opens the next bucket. LATEST can expose the
current partial compacted bucket in range queries. A partial
bucket is not equivalent to a closed period and should be
labeled accordingly in dashboards.
6. Wrong approach: assume compaction can replace raw truth immediately
Suppose AtlasMart keeps only one-minute averages, then an incident asks whether temperature briefly exceeded 8.5°C for five seconds. The average may hide the excursion. Downsampling is a loss of detail even when the reducer is exact for its bucket.
docker exec -e REDISCLI_AUTH=AtlasMart-App-Lab-Only-2026 atlasmart-redis-ch01 redis-cli --user atlasmart-app TS.RANGE atlasmart:ch12:raw:temp:baku-01:s01 0 59999docker exec -e REDISCLI_AUTH=AtlasMart-App-Lab-Only-2026 atlasmart-redis-ch01 redis-cli --user atlasmart-app TS.RANGE atlasmart:ch12:raw:temp:baku-01:s01 0 59999 AGGREGATION avg 60000docker exec -e REDISCLI_AUTH=AtlasMart-App-Lab-Only-2026 atlasmart-redis-ch01 redis-cli --user atlasmart-app TS.RANGE atlasmart:ch12:raw:temp:baku-01:s01 0 59999 AGGREGATION max 60000
The repair is a retention hierarchy: preserve raw samples for the investigation horizon, maintain appropriate derived aggregates for longer horizons, and document which questions each tier can answer. Do not select retention values by folklore; derive them from audit, incident, cost, and query requirements.
7. Multi-series queries select by labels, then aggregate samples
docker exec -e REDISCLI_AUTH=AtlasMart-App-Lab-Only-2026 atlasmart-redis-ch01 redis-cli --user atlasmart-app TS.QUERYINDEX tenant=atlasmart site=baku-01 metric=temperaturedocker exec -e REDISCLI_AUTH=AtlasMart-App-Lab-Only-2026 atlasmart-redis-ch01 redis-cli --user atlasmart-app TS.MRANGE 0 120000 WITHLABELS COUNT 10 FILTER tenant=atlasmart site=baku-01 metric=temperaturedocker exec -e REDISCLI_AUTH=AtlasMart-App-Lab-Only-2026 atlasmart-redis-ch01 redis-cli --user atlasmart-app TS.MRANGE 0 120000 WITHLABELS AGGREGATION avg 60000 FILTER tenant=atlasmart site=baku-01 metric=temperature
FILTER first chooses matching series by labels;
aggregation then operates on each selected series.
COUNT bounds samples/buckets per series, but total
reply size still grows with the number of matching series.
8. GROUPBY/REDUCE performs cross-series aggregation after per-series work
docker exec -e REDISCLI_AUTH=AtlasMart-App-Lab-Only-2026 atlasmart-redis-ch01 redis-cli --user atlasmart-app TS.MRANGE 0 120000 WITHLABELS AGGREGATION avg 60000 FILTER tenant=atlasmart site=baku-01 metric=temperature GROUPBY zone REDUCE avgdocker exec -e REDISCLI_AUTH=AtlasMart-App-Lab-Only-2026 atlasmart-redis-ch01 redis-cli --user atlasmart-app TS.MRANGE 0 120000 WITHLABELS FILTER tenant=atlasmart site=baku-01 metric=temperature GROUPBY zone REDUCE max
GROUPBY zone REDUCE avg is appropriate only if zone
has a controlled vocabulary and averaging sensor outputs is
meaningful. A reducer can be mathematically valid but
semantically wrong—for example averaging counters that should be
summed.
9. Redis 8.10 adds new Time Series query/read surfaces
Redis 8.10 adds TS.NRANGE/TS.NREVRANGE
(results grouped by timestamp), TS.READ (optionally
blocking reads), TS.QUERYLABELS, and
EXCLUDEEMPTY for multi-range queries. These are
useful current capabilities, but they are version-sensitive
extensions rather than assumptions for clients targeting older
Redis 8.x deployments.
docker exec -e REDISCLI_AUTH=AtlasMart-Admin-Lab-Only-2026 atlasmart-redis-ch01 redis-cli --user academy-admin COMMAND INFO TS.NRANGE TS.NREVRANGE TS.READ TS.QUERYLABELS TS.MRANGE
Client-library wrappers may not immediately expose new server commands. Raw command execution is a learning fallback, not an excuse to skip client compatibility tests.
10. Memory, query width, and compaction fan-out are capacity dimensions
docker exec -e REDISCLI_AUTH=AtlasMart-App-Lab-Only-2026 atlasmart-redis-ch01 redis-cli --user atlasmart-app MEMORY USAGE atlasmart:ch12:raw:temp:baku-01:s01docker exec -e REDISCLI_AUTH=AtlasMart-App-Lab-Only-2026 atlasmart-redis-ch01 redis-cli --user atlasmart-app MEMORY USAGE atlasmart:ch12:raw:temp:baku-01:s02docker exec -e REDISCLI_AUTH=AtlasMart-App-Lab-Only-2026 atlasmart-redis-ch01 redis-cli --user atlasmart-app MEMORY USAGE atlasmart:ch12:rollup:rule-demo:temp:baku-01:s01:1mdocker exec -e REDISCLI_AUTH=AtlasMart-Admin-Lab-Only-2026 atlasmart-redis-ch01 redis-cli --user academy-admin INFO commandstatsdocker exec -e REDISCLI_AUTH=AtlasMart-Admin-Lab-Only-2026 atlasmart-redis-ch01 redis-cli --user academy-admin INFO latencystats
Measure memory per source series, memory per derived series, number of rules per source, query series matched, buckets returned, and tail latency under concurrent writes. One tiny lab cannot produce a universal safe series count.
11. Cleanup the rule before deleting its keys
docker exec -e REDISCLI_AUTH=AtlasMart-App-Lab-Only-2026 atlasmart-redis-ch01 redis-cli --user atlasmart-app TS.DELETERULE atlasmart:ch12:raw:rule-demo:temp:baku-01:s01 atlasmart:ch12:rollup:rule-demo:temp:baku-01:s01:1mdocker exec -e REDISCLI_AUTH=AtlasMart-Admin-Lab-Only-2026 atlasmart-redis-ch01 redis-cli --user academy-admin UNLINK atlasmart:ch12:raw:temp:baku-01:s01 atlasmart:ch12:raw:temp:baku-01:s02 atlasmart:ch12:raw:rule-demo:temp:baku-01:s01 atlasmart:ch12:rollup:rule-demo:temp:baku-01:s01:1m
Deleting the explicit rule first keeps the reset understandable. On a disposable fixture, deleting keys may also remove rule state, but the lab teaches the lifecycle you should reason about operationally.
12. Production judgment
Use server-side range aggregation when the reducer and bucket contract are stable and moving fewer samples over the network materially helps. Use compaction when derived summaries are repeatedly queried and their lineage/retention are explicit. Avoid high-cardinality labels, unbounded multi-series replies, and compaction rule explosions. In replication and persistence, every source and derived write adds downstream work. In Cluster or managed services, verify multi-series behavior, routing, quotas, and client support on the actual target topology. Preserve a rebuild path for derived series.
Check your understanding
- What changes when ALIGN changes?
- Why is a compaction destination not raw truth?
- What does COUNT bound in TS.MRANGE?
- Why can GROUPBY on a user ID be dangerous?
- What is the operational benefit of treating rollups as rebuildable?
Review the answers
Which raw samples belong to each bucket, and therefore potentially the aggregate values and reported timestamps.
It stores derived bucket summaries and intentionally loses sample-level detail.
Samples/buckets per selected series, not the number of matching series.
It can create effectively unbounded groups and high metadata/query cardinality.
You can change rules, recover corruption, migrate versions, or backfill without pretending derived state is irreplaceable.
13. Summary and next step
You can now distinguish raw range reads, on-demand aggregation, persistent compaction, cross-series selection, and cross-series reduction. Lesson 3 shifts from time to space and builds a location index with correct coordinate order, distance units, radius/box queries, and precision limits.
Authoritative references
- Redis Open Source 8.10 release notes
- Redis 8.10 command reference
- Redis Time Series data type
- Time Series configuration
- TS.CREATE
- TS.ADD
- TS.INFO
- TS.RANGE
- TS.MRANGE
- TS.CREATERULE
- TS.QUERYINDEX
- Redis geospatial data type
- GEOADD
- GEOSEARCH
- GEODIST
- MEMORY USAGE
- INFO
- Redis 8.10 what’s new
- TS.MGET
- TS.DELETERULE