Combine sorted-set membership and scores with weighted union/intersection/difference while respecting cost, version, and Cluster locality.
ZUNION/ZINTER/ZDIFF and Weighted Ranking Aggregation
Choose hashes, Redis JSON, or many keys from structure, update/query patterns, expiration granularity, memory/cardinality, indexing, ACL boundaries, and migration evidence.
Learning outcomes
AtlasMart maintains several ranked signals—sales, conversion quality, and support satisfaction—and wants combined rankings plus cohort intersections. Redis can derive new sorted sets or return derived results directly, but weighted aggregation has precise score semantics and multi-key/topology cost.
Use ZUNION, ZINTER, and ZDIFF with exact membership semantics.
Apply WEIGHTS and SUM/MIN/MAX aggregation and interpret resulting scores.
Explain the Redis 8.8+ COUNT aggregate as a version-sensitive extension.
Measure input cardinality/result size instead of treating multi-set algebra as cheap.
Plan Redis Cluster hash-slot locality for multi-key sorted-set operations.
All Chapter 06 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 ACL users atlasmart-app and
academy-admin, logical database 0, AOF with
appendfsync everysec plus RDB snapshots,
persistent /data volume, and no explicit Redis
maxmemory limit or eviction policy. The primary
interface is the redis-cli shipped in the same
pinned image. Mandatory examples use only bounded synthetic
keys under atlasmart:ch06:*.
1. Union merges membership and aggregates overlapping scores
ZUNION returns every member that appears in at
least one input sorted set. When a member appears in multiple
inputs, the default SUM aggregate combines its
weighted scores.
docker exec -e REDISCLI_AUTH=AtlasMart-App-Lab-Only-2026 atlasmart-redis-ch01 redis-cli --user atlasmart-app DEL atlasmart:ch06:sales atlasmart:ch06:qualitydocker exec -e REDISCLI_AUTH=AtlasMart-App-Lab-Only-2026 atlasmart-redis-ch01 redis-cli --user atlasmart-app ZADD atlasmart:ch06:sales 10 a 20 b 30 cdocker exec -e REDISCLI_AUTH=AtlasMart-App-Lab-Only-2026 atlasmart-redis-ch01 redis-cli --user atlasmart-app ZADD atlasmart:ch06:quality 4 b 8 c 16 ddocker exec -e REDISCLI_AUTH=AtlasMart-App-Lab-Only-2026 atlasmart-redis-ch01 redis-cli --user atlasmart-app ZUNION 2 atlasmart:ch06:sales atlasmart:ch06:quality WITHSCORES
The result contains a, b, c, and d. Members b and c receive sums from both inputs. The result is returned to the client; STORE variants persist a derived key.
2. WEIGHTS transform each input before aggregation
WEIGHTS multiplies each input score by its
corresponding factor before the aggregate is applied. This is
mathematically simple but operationally dangerous if
stakeholders treat arbitrary weights as objective truth.
Normalize input scales deliberately.
docker exec -e REDISCLI_AUTH=AtlasMart-App-Lab-Only-2026 atlasmart-redis-ch01 redis-cli --user atlasmart-app ZUNION 2 atlasmart:ch06:sales atlasmart:ch06:quality WEIGHTS 0.7 0.3 AGGREGATE SUM WITHSCORESdocker exec -e REDISCLI_AUTH=AtlasMart-App-Lab-Only-2026 atlasmart-redis-ch01 redis-cli --user atlasmart-app ZUNION 2 atlasmart:ch06:sales atlasmart:ch06:quality WEIGHTS 1 1 AGGREGATE MAX WITHSCORESdocker exec -e REDISCLI_AUTH=AtlasMart-App-Lab-Only-2026 atlasmart-redis-ch01 redis-cli --user atlasmart-app ZUNION 2 atlasmart:ch06:sales atlasmart:ch06:quality WEIGHTS 1 1 AGGREGATE MIN WITHSCORES
SUM combines contributions; MAX/MIN choose the maximum/minimum transformed score among inputs where the member exists. Weight choice belongs in a versioned ranking policy, not in an unexplained command literal.
3. Intersection changes membership before score aggregation
ZINTER keeps only members present in every input.
It then applies weights and aggregation to those surviving
members. This is useful for “rank only customers who belong to
every required cohort,” but the smallest input set and number of
inputs affect worst-case cost.
docker exec -e REDISCLI_AUTH=AtlasMart-App-Lab-Only-2026 atlasmart-redis-ch01 redis-cli --user atlasmart-app ZINTER 2 atlasmart:ch06:sales atlasmart:ch06:quality WITHSCORESdocker exec -e REDISCLI_AUTH=AtlasMart-App-Lab-Only-2026 atlasmart-redis-ch01 redis-cli --user atlasmart-app ZINTER 2 atlasmart:ch06:sales atlasmart:ch06:quality WEIGHTS 2 1 AGGREGATE SUM WITHSCORESdocker exec -e REDISCLI_AUTH=AtlasMart-App-Lab-Only-2026 atlasmart-redis-ch01 redis-cli --user atlasmart-app ZCARD atlasmart:ch06:salesdocker exec -e REDISCLI_AUTH=AtlasMart-App-Lab-Only-2026 atlasmart-redis-ch01 redis-cli --user atlasmart-app ZCARD atlasmart:ch06:quality
Only b and c survive the example. The documentation classifies ZINTER as a slow command because cost grows with input/result cardinality.
4. Difference is membership subtraction, not score subtraction
ZDIFF returns members in the first sorted set that
do not appear in subsequent sets. It does not subtract scores.
docker exec -e REDISCLI_AUTH=AtlasMart-App-Lab-Only-2026 atlasmart-redis-ch01 redis-cli --user atlasmart-app ZDIFF 2 atlasmart:ch06:sales atlasmart:ch06:quality WITHSCORESdocker exec -e REDISCLI_AUTH=AtlasMart-App-Lab-Only-2026 atlasmart-redis-ch01 redis-cli --user atlasmart-app ZDIFF 2 atlasmart:ch06:quality atlasmart:ch06:sales WITHSCORES
The direction matters. “sales minus quality” and “quality minus sales” are different membership sets.
5. Redis 8.8+ COUNT aggregate is version-sensitive
Current Redis 8.10.1 documentation includes
AGGREGATE COUNT for ZUNION/ZINTER and their STORE
variants, added in Redis 8.8. With COUNT, the resulting score
reflects how many input sets contributed the member rather than
SUM/MIN/MAX score arithmetic. Because this is newer than many
Redis deployments and client wrappers, check
INFO server, COMMAND INFO, and client
support before relying on it.
6. Version evidence before using newer aggregation
Do not infer command options from a course screenshot. Ask the server you are connected to.
docker exec -e REDISCLI_AUTH=AtlasMart-App-Lab-Only-2026 atlasmart-redis-ch01 redis-cli --user atlasmart-app INFO serverdocker exec -e REDISCLI_AUTH=AtlasMart-App-Lab-Only-2026 atlasmart-redis-ch01 redis-cli --user atlasmart-app COMMAND INFO ZUNIONdocker exec -e REDISCLI_AUTH=AtlasMart-App-Lab-Only-2026 atlasmart-redis-ch01 redis-cli --user atlasmart-app ZUNION 2 atlasmart:ch06:sales atlasmart:ch06:quality AGGREGATE COUNT WITHSCORES
In the pinned 8.10.1 lab, COUNT should be available. On an older server or managed service with different compatibility, the command may fail even if your client library has a method signature for it.
7. Wrong approach: huge synchronous aggregation on hot global keys
Multi-key sorted-set algebra can read many members and construct a large result. Returning millions of derived members to one client can consume CPU, memory, network bandwidth, and tail-latency budget. Storing a derived result can also duplicate substantial memory.
docker exec -e REDISCLI_AUTH=AtlasMart-App-Lab-Only-2026 atlasmart-redis-ch01 redis-cli --user atlasmart-app ZCARD atlasmart:ch06:salesdocker exec -e REDISCLI_AUTH=AtlasMart-App-Lab-Only-2026 atlasmart-redis-ch01 redis-cli --user atlasmart-app ZCARD atlasmart:ch06:qualitydocker exec -e REDISCLI_AUTH=AtlasMart-App-Lab-Only-2026 atlasmart-redis-ch01 redis-cli --user atlasmart-app MEMORY USAGE atlasmart:ch06:salesdocker exec -e REDISCLI_AUTH=AtlasMart-App-Lab-Only-2026 atlasmart-redis-ch01 redis-cli --user atlasmart-app MEMORY USAGE atlasmart:ch06:qualitydocker exec -e REDISCLI_AUTH=AtlasMart-App-Lab-Only-2026 atlasmart-redis-ch01 redis-cli --user atlasmart-app ZUNION 2 atlasmart:ch06:sales atlasmart:ch06:quality WITHSCORES
Repair by bounding cohorts, precomputing intentionally, sampling/benchmarking realistic sizes, or redesigning the ranking pipeline. Never extrapolate this tiny fixture's latency to production.
8. Stored versus returned results
ZUNION/ZINTER/ZDIFF
return results. STORE variants write a destination key and
replace its previous value. Stored derived rankings introduce
lifecycle questions: who refreshes them, how long are they
valid, what happens during partial update, and how are stale
results removed? Derived keys are not automatically synchronized
views.
9. Redis Cluster: all participating keys must be routable together
Multi-key commands in Redis Cluster have slot-locality
constraints. Hash tags can deliberately co-locate related keys,
for example atlasmart:{region:az}:sales and
atlasmart:{region:az}:quality. That enables
same-region aggregation but can also concentrate traffic. Do not
add a common global hash tag merely to make every multi-key
command legal; that can destroy distribution.
10. Ranking policy table
| Choice | Meaning | Risk to document |
|---|---|---|
| SUM | add transformed scores | scale dominance / double-counting |
| MIN | weakest contributing score | different meaning from “minimum across all entities” |
| MAX | strongest contributing score | can ignore weaker signals |
| COUNT (8.8+) | number of contributing inputs | version/client compatibility |
| ZDIFF | membership subtraction | direction matters; scores not subtracted |
11. Reproducible weighted-ranking lab
Build three small signals, derive union/intersection/difference, then remove them.
docker exec -e REDISCLI_AUTH=AtlasMart-App-Lab-Only-2026 atlasmart-redis-ch01 redis-cli --user atlasmart-app DEL atlasmart:ch06:lab:s1 atlasmart:ch06:lab:s2 atlasmart:ch06:lab:s3docker exec -e REDISCLI_AUTH=AtlasMart-App-Lab-Only-2026 atlasmart-redis-ch01 redis-cli --user atlasmart-app ZADD atlasmart:ch06:lab:s1 10 u:a 20 u:b 30 u:cdocker exec -e REDISCLI_AUTH=AtlasMart-App-Lab-Only-2026 atlasmart-redis-ch01 redis-cli --user atlasmart-app ZADD atlasmart:ch06:lab:s2 5 u:b 9 u:c 11 u:ddocker exec -e REDISCLI_AUTH=AtlasMart-App-Lab-Only-2026 atlasmart-redis-ch01 redis-cli --user atlasmart-app ZADD atlasmart:ch06:lab:s3 1 u:c 2 u:d 3 u:edocker exec -e REDISCLI_AUTH=AtlasMart-App-Lab-Only-2026 atlasmart-redis-ch01 redis-cli --user atlasmart-app ZUNION 3 atlasmart:ch06:lab:s1 atlasmart:ch06:lab:s2 atlasmart:ch06:lab:s3 WEIGHTS 1 2 3 AGGREGATE SUM WITHSCORESdocker exec -e REDISCLI_AUTH=AtlasMart-App-Lab-Only-2026 atlasmart-redis-ch01 redis-cli --user atlasmart-app ZINTER 3 atlasmart:ch06:lab:s1 atlasmart:ch06:lab:s2 atlasmart:ch06:lab:s3 WITHSCORESdocker exec -e REDISCLI_AUTH=AtlasMart-App-Lab-Only-2026 atlasmart-redis-ch01 redis-cli --user atlasmart-app ZDIFF 2 atlasmart:ch06:lab:s1 atlasmart:ch06:lab:s2 WITHSCORES
Verification: only u:c appears in all three. Difference s1−s2 contains only u:a. Compute expected weighted scores manually before trusting any ranking policy.
12. Production judgment
Weighted sorted-set algebra is appropriate for bounded, explicit ranking derivations whose score scales and membership meaning are understood. It is not a substitute for analytical databases, offline feature pipelines, or full ranking evaluation. Benchmark realistic cardinality/skew, measure output size and p99 latency, define derived-key freshness, and make Cluster locality deliberate. Treat new options such as COUNT as version-gated.
13. Summary and next step
Union, intersection, and difference combine membership; weights and aggregation define derived scores. Next, we use sorted sets as operational secondary indexes for rate limits, schedulers, expiration indexes, and other access paths—while separating the index from the source of truth.
Check your understanding
- What membership does ZINTER return?
- What happens before SUM/MIN/MAX when WEIGHTS are used?
- Does ZDIFF subtract numeric scores?
- When was AGGREGATE COUNT added?
- Why do Cluster hash tags need restraint?
Review the answers
Only members present in every input set.
Each input score is multiplied by its corresponding weight.
No. It subtracts membership from the first input.
Redis 8.8.
Co-locating everything under one hash tag can create a hot slot and defeat distribution.
Authoritative references
- Redis sorted sets — data model, score/rank behavior, and common patterns
- ZADD — conditional updates, score precision, and return behavior
- ZRANGE — rank, BYSCORE, BYLEX, REV, LIMIT, and WITHSCORES
- ZINCRBY — relative score updates
- ZUNION — weighted unions and aggregation
- ZINTER — weighted intersections and complexity
- ZDIFF — sorted-set difference semantics
- Redis Cluster specification — slot locality for multi-key commands
- Redis Open Source 8.10 release notes — pinned course release family