Compose Redis Sets with union, intersection, and difference while making cardinality, Cluster locality, and freshness cost explicit.
SUNION/SINTER/SDIFF and Set Algebra for Tags, Audiences, and Permissions
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 wants audiences such as “VIP customers who opted into email but are not suppressed” and permission sets such as “operators allowed for store 42.” Redis Set algebra can compute these relations directly, but the output size and number/cardinality of input sets determine work.
Compute SUNION, SINTER, and SDIFF and interpret missing-key behavior.
Reason from documented command complexity instead of assuming all Set operations are O(1).
Use cardinality-only variants when the question asks only “how many?” and verify server version.
Design Cluster hash tags for same-slot multi-key algebra without creating accidental hot-slot concentration.
Use set-derived permissions/audiences with explicit freshness, source-of-truth, and rollback policy.
All Chapter 05 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
application ACL is restricted to ~atlasmart:* and
normal read/write/connection categories. The primary interface
is the redis-cli shipped in the same 8.10.1
image, so server and CLI versions stay aligned. Mandatory
examples use only bounded synthetic keys under
atlasmart:ch05:*.
1. Union, intersection, and difference answer different questions
SUNION returns members present in any input set.
SINTER returns only members present in every input
set. SDIFF A B C is directional: it returns members
of A that are absent from B and C. Missing keys are treated as
empty sets, which changes intersection and difference in
predictable ways.
docker exec -e REDISCLI_AUTH=AtlasMart-App-Lab-Only-2026 atlasmart-redis-ch01 redis-cli --user atlasmart-app DEL atlasmart:ch05:{fall}:vip atlasmart:ch05:{fall}:email atlasmart:ch05:{fall}:suppresseddocker exec -e REDISCLI_AUTH=AtlasMart-App-Lab-Only-2026 atlasmart-redis-ch01 redis-cli --user atlasmart-app SADD atlasmart:ch05:{fall}:vip c1 c2 c3 c4docker exec -e REDISCLI_AUTH=AtlasMart-App-Lab-Only-2026 atlasmart-redis-ch01 redis-cli --user atlasmart-app SADD atlasmart:ch05:{fall}:email c2 c3 c4 c5docker exec -e REDISCLI_AUTH=AtlasMart-App-Lab-Only-2026 atlasmart-redis-ch01 redis-cli --user atlasmart-app SADD atlasmart:ch05:{fall}:suppressed c4docker exec -e REDISCLI_AUTH=AtlasMart-App-Lab-Only-2026 atlasmart-redis-ch01 redis-cli --user atlasmart-app SUNION atlasmart:ch05:{fall}:vip atlasmart:ch05:{fall}:emaildocker exec -e REDISCLI_AUTH=AtlasMart-App-Lab-Only-2026 atlasmart-redis-ch01 redis-cli --user atlasmart-app SINTER atlasmart:ch05:{fall}:vip atlasmart:ch05:{fall}:emaildocker exec -e REDISCLI_AUTH=AtlasMart-App-Lab-Only-2026 atlasmart-redis-ch01 redis-cli --user atlasmart-app SDIFF atlasmart:ch05:{fall}:vip atlasmart:ch05:{fall}:suppressed
Set reply ordering is not a stable business ordering. Compare membership, not display sequence.
2. Cost follows cardinality, not command-name simplicity
Current Redis documentation classifies these algebra commands as
slow relative to constant-time membership primitives.
SUNION and SDIFF are O(N) in the total
elements considered. SINTER is O(N×M) worst case
where N is the cardinality of the smallest set and M is the
number of sets. Returning a huge result also costs memory,
serialization, network bandwidth, and client decoding.
docker exec -e REDISCLI_AUTH=AtlasMart-App-Lab-Only-2026 atlasmart-redis-ch01 redis-cli --user atlasmart-app SCARD atlasmart:ch05:{fall}:vipdocker exec -e REDISCLI_AUTH=AtlasMart-App-Lab-Only-2026 atlasmart-redis-ch01 redis-cli --user atlasmart-app SCARD atlasmart:ch05:{fall}:emaildocker exec -e REDISCLI_AUTH=AtlasMart-App-Lab-Only-2026 atlasmart-redis-ch01 redis-cli --user atlasmart-app SCARD atlasmart:ch05:{fall}:suppresseddocker exec -e REDISCLI_AUTH=AtlasMart-App-Lab-Only-2026 atlasmart-redis-ch01 redis-cli --user atlasmart-app MEMORY USAGE atlasmart:ch05:{fall}:vip
Do not invent a universal “safe cardinality.” Record real cardinalities, payload sizes, p50/p95/p99 latency, concurrency, and Cluster topology for your workload.
3. Ask for cardinality when you do not need the members
SINTERCARD has existed since Redis 7.0 and returns
only intersection cardinality. Redis 8.10 adds
SUNIONCARD and SDIFFCARD. These avoid
transferring the full result when the business question is “how
many?”, though the server still must perform the relevant set
computation.
docker exec -e REDISCLI_AUTH=AtlasMart-Admin-Lab-Only-2026 atlasmart-redis-ch01 redis-cli --user academy-admin COMMAND INFO SINTERCARD SUNIONCARD SDIFFCARDdocker exec -e REDISCLI_AUTH=AtlasMart-App-Lab-Only-2026 atlasmart-redis-ch01 redis-cli --user atlasmart-app SINTERCARD 2 atlasmart:ch05:{fall}:vip atlasmart:ch05:{fall}:emaildocker exec -e REDISCLI_AUTH=AtlasMart-App-Lab-Only-2026 atlasmart-redis-ch01 redis-cli --user atlasmart-app SUNIONCARD 2 atlasmart:ch05:{fall}:vip atlasmart:ch05:{fall}:emaildocker exec -e REDISCLI_AUTH=AtlasMart-App-Lab-Only-2026 atlasmart-redis-ch01 redis-cli --user atlasmart-app SDIFFCARD 2 atlasmart:ch05:{fall}:vip atlasmart:ch05:{fall}:suppressed
The two 8.10 commands are version-sensitive extensions. Capability-check them before depending on a managed/proxy/older server.
4. Store variants materialize a derived Set—and create freshness work
SINTERSTORE, SUNIONSTORE, and
SDIFFSTORE write the derived result to a
destination key. This can move repeated computation off a read
path, but it creates a materialized view whose refresh,
invalidation, TTL, ACL, and rollback must be designed.
docker exec -e REDISCLI_AUTH=AtlasMart-App-Lab-Only-2026 atlasmart-redis-ch01 redis-cli --user atlasmart-app SINTERSTORE atlasmart:ch05:{fall}:eligible atlasmart:ch05:{fall}:vip atlasmart:ch05:{fall}:emaildocker exec -e REDISCLI_AUTH=AtlasMart-App-Lab-Only-2026 atlasmart-redis-ch01 redis-cli --user atlasmart-app SREM atlasmart:ch05:{fall}:eligible c4docker exec -e REDISCLI_AUTH=AtlasMart-App-Lab-Only-2026 atlasmart-redis-ch01 redis-cli --user atlasmart-app SMEMBERS atlasmart:ch05:{fall}:eligibledocker exec -e REDISCLI_AUTH=AtlasMart-App-Lab-Only-2026 atlasmart-redis-ch01 redis-cli --user atlasmart-app EXPIRE atlasmart:ch05:{fall}:eligible 600
The manual SREM c4 illustrates why ad hoc
post-processing is fragile. A better design encodes the
suppression relation in a reproducible computation such as an
intersection followed by difference, or computes it in a
transaction/function/application pipeline with a versioned
source snapshot.
5. Cluster: multi-key algebra requires key locality
Redis Cluster partitions keys into 16,384 hash slots. Multi-key
operations generally require the participating keys to be in the
same slot. Hash tags—the substring inside {...}—let
related keys intentionally share a slot. The lab keys use
{fall} for that reason.
Do not tag an entire global tenant or every campaign with one
constant just to silence CROSSSLOT; that can
concentrate traffic and memory into one slot. Choose a locality
boundary that matches the operation and expected scale, then
measure slot distribution.
6. Permissions: fast membership is not the whole authorization system
Sets are attractive for roles and permissions because
SISMEMBER is fast and algebra is expressive. But a
stale Redis permission set can grant access after the source
policy revoked it. Treat Redis as a derived authorization cache
only when versioning/invalidation, fail-closed behavior, audit
evidence, and source-of-truth reconciliation are explicit.
docker exec -e REDISCLI_AUTH=AtlasMart-App-Lab-Only-2026 atlasmart-redis-ch01 redis-cli --user atlasmart-app DEL atlasmart:ch05:{store42}:role:manager atlasmart:ch05:{store42}:perm:refunddocker exec -e REDISCLI_AUTH=AtlasMart-App-Lab-Only-2026 atlasmart-redis-ch01 redis-cli --user atlasmart-app SADD atlasmart:ch05:{store42}:role:manager user:a user:bdocker exec -e REDISCLI_AUTH=AtlasMart-App-Lab-Only-2026 atlasmart-redis-ch01 redis-cli --user atlasmart-app SADD atlasmart:ch05:{store42}:perm:refund user:b user:cdocker exec -e REDISCLI_AUTH=AtlasMart-App-Lab-Only-2026 atlasmart-redis-ch01 redis-cli --user atlasmart-app SINTER atlasmart:ch05:{store42}:role:manager atlasmart:ch05:{store42}:perm:refund
The intersection answers the data question on the current Redis state; it does not prove that state is current enough to authorize a real refund.
7. Deliberately wrong: huge synchronous algebra on a hot request path
A request handler that executes SINTER across
several million-member sets and returns all matches can
monopolize server execution time and generate a massive
response. The syntax is short; the work is not.
Do not generate million-member sets in this course lab. Use small fixtures to prove semantics, then use cardinality and staging benchmarks in a disposable performance environment to establish production limits.
docker exec -e REDISCLI_AUTH=AtlasMart-App-Lab-Only-2026 atlasmart-redis-ch01 redis-cli --user atlasmart-app SINTER atlasmart:ch05:{fall}:vip atlasmart:ch05:{fall}:emaildocker exec -e REDISCLI_AUTH=AtlasMart-App-Lab-Only-2026 atlasmart-redis-ch01 redis-cli --user atlasmart-app SINTERCARD 2 atlasmart:ch05:{fall}:vip atlasmart:ch05:{fall}:email LIMIT 1
Repair options include cardinality-only queries, precomputed/materialized audiences, background recomputation, smaller partitioned sets, or a different analytical system when the workload is fundamentally batch/large-scale.
8. Hands-on lab: audience decision record
Compute “VIP ∩ email − suppressed” and verify every intermediate cardinality.
docker exec -e REDISCLI_AUTH=AtlasMart-App-Lab-Only-2026 atlasmart-redis-ch01 redis-cli --user atlasmart-app SINTERSTORE atlasmart:ch05:{fall}:vip-email atlasmart:ch05:{fall}:vip atlasmart:ch05:{fall}:emaildocker exec -e REDISCLI_AUTH=AtlasMart-App-Lab-Only-2026 atlasmart-redis-ch01 redis-cli --user atlasmart-app SDIFFSTORE atlasmart:ch05:{fall}:send atlasmart:ch05:{fall}:vip-email atlasmart:ch05:{fall}:suppresseddocker exec -e REDISCLI_AUTH=AtlasMart-App-Lab-Only-2026 atlasmart-redis-ch01 redis-cli --user atlasmart-app SCARD atlasmart:ch05:{fall}:senddocker exec -e REDISCLI_AUTH=AtlasMart-App-Lab-Only-2026 atlasmart-redis-ch01 redis-cli --user atlasmart-app SMEMBERS atlasmart:ch05:{fall}:senddocker exec -e REDISCLI_AUTH=AtlasMart-App-Lab-Only-2026 atlasmart-redis-ch01 redis-cli --user atlasmart-app MEMORY USAGE atlasmart:ch05:{fall}:send
Record source cardinalities, result cardinality, hash-tag locality assumption, result TTL policy, and how the derived audience will be invalidated if a source Set changes.
9. Production judgment
Set algebra is excellent for bounded, key-local membership relations. Keep large synchronous results off latency-sensitive paths unless measurements justify them. In Cluster, design slot locality deliberately. For authorization and regulated audiences, preserve an authoritative source and an auditable refresh/version story. When the relation needs ranked output, time ordering, or durable change history, another structure may be more appropriate.
10. Summary and next step
Union, intersection, and difference make Sets composable, but cardinality determines real cost and Cluster determines where multi-key operations are legal. The final lesson turns these mechanics into a structure-selection decision across Lists, Sets, Streams, and Sorted Sets.
Check your understanding
- What happens to SINTER when one input key does not exist?
- Why can SUNION be expensive even though SADD is O(1) per member?
- When should you prefer SINTERCARD over SINTER?
- Why do {hash tags} matter in Redis Cluster?
- Why should a Redis permission Set usually have a source-of-truth/versioning story?
Review the answers
A missing Set is treated as empty, so the intersection is empty.
SUNION must examine members across all inputs and may return a large result; operation complexity differs from membership insertion.
When you need only the count, avoiding the full member reply reduces network/client result cost.
They force related keys into the same hash slot so multi-key operations can be legal; poor tag design can create hotspots.
Cached permissions can become stale after policy changes; correctness and auditability require freshness and reconciliation guarantees.
Authoritative references
- Redis Open Source 8.10 release notes — 8.10.1 security baseline and 8.10 list/set additions
- Redis lists — list semantics and common queue patterns
- Redis sets — set uniqueness, membership, and algebra
- Redis Streams — persistent entries, consumer groups, pending entries, and acknowledgments
- Redis 8.10 command reference — current command syntax and complexity
- Redis Cluster specification — hash slots and multi-key locality
- SUNION — union semantics and O(N) cost
- SINTER — intersection semantics and worst-case complexity
- SDIFF — directional difference semantics and cost
- SINTERCARD — cardinality-only intersection and LIMIT