Find Set Intersections & Unions
Learn how to use Redis commands to find intersections and unions of sets, with hands-on exercises and troubleshooting tips.
Focus: find set intersections and unions
Have you ever needed to compare two sets of data — like finding which users are in both a beta group and a VIP list, or combining the tags from multiple articles? Manually looping through lists in Python or writing complex SQL is slow and error-prone. Redis Sets come to the rescue with built-in commands like SINTER, SUNION, and SDIFF that perform these operations instantly in-memory, giving you results in milliseconds.
The Problem This Lesson Solves
When working with collections of unique elements, you often need to find common members, merge sets, or identify differences. Without a dedicated tool, you'd write nested loops or use hash-based lookups that are fragile and slow as data grows. Redis Sets are designed exactly for this: they store unique strings and offer atomic set operations that run at server-side speed, saving you from moving data back and forth.
Core Concept / Mental Model
Think of Redis Sets as mathematical sets — unordered collections of unique items. The four key operations mirror their math counterparts:
- Union (SUNION) – all items from Set A and Set B, with duplicates removed.
- Intersection (SINTER) – items that appear in both Set A and Set B.
- Difference (SDIFF) – items in Set A but not in Set B.
- Difference (SDIFFSTORE, SINTERSTORE, SUNIONSTORE) – store the result into a new Set for later use.
💡 Pro tip: All these operations are O(N) where N is the combined size of the input sets. For large sets (millions), the server still delivers sub‑millisecond responses — but avoid storing the result into a key you immediately delete.
The Commands at a Glance
| Command | Purpose | Returns |
|---|---|---|
SINTER key [key ...] |
Intersection of two or more Sets | Set of members present in all |
SUNION key [key ...] |
Union of two or more Sets | Set of all distinct members |
SDIFF key [key ...] |
Difference of first Set minus the rest | Members in first but not others |
SINTERSTORE dest key [key ...] |
Intersection stored in dest |
Integer (size of result) |
SUNIONSTORE dest key [key ...] |
Union stored in dest |
Integer (size of result) |
SDIFFSTORE dest key [key ...] |
Difference stored in dest |
Integer (size of result) |
How It Works Step by Step
- Add members to one or more Sets using
SADD. - Call the desired operation —
SINTER,SUNION, orSDIFF— passing the Set keys in order. - Examine the result – it's a Set, so you can use
SMEMBERSto view it (or use the result inline). - Optionally persist the result with
*STOREvariants to avoid recomputing expensive operations.
RDBMS Analogy
In SQL, intersection is INNER JOIN on unique IDs. Union is UNION DISTINCT. Redis performs these joins server-side without transferring data — much faster for real‑time scenarios like analytics dashboards.
Hands-On Walkthrough
Let's build a real scenario: you have two customer segments — beta_users and vip_users. You need to find overlapping users, merge them, and identify non‑VIP beta testers.
Example 1: Basic Intersection and Union
import redis
r = redis.Redis(host='localhost', port=6379, decode_responses=True)
# Create sets
r.delete('beta_users', 'vip_users')
r.sadd('beta_users', 'alice', 'bob', 'charlie', 'diana')
r.sadd('vip_users', 'bob', 'diana', 'eve', 'frank')
# Intersection — users in both groups
common = r.sinter('beta_users', 'vip_users')
print("Beta & VIP intersection:", sorted(common))
# Output: Beta & VIP intersection: ['bob', 'diana']
# Union — all users combined
all_users = r.sunion('beta_users', 'vip_users')
print("All users (union):", sorted(all_users))
# Output: All users (union): ['alice', 'bob', 'charlie', 'diana', 'eve', 'frank']
Example 2: Difference and Store
# Beta users NOT in VIP
beta_only = r.sdiff('beta_users', 'vip_users')
print("Beta only:", sorted(beta_only))
# Output: Beta only: ['alice', 'charlie']
# Store union for later analytics
r.sunionstore('all_customers', 'beta_users', 'vip_users')
print("Stored union size:", r.scard('all_customers'))
# Output: Stored union size: 6
# Clean up
r.delete('beta_users', 'vip_users', 'all_customers')
Example 3: Command Line with redis-cli
# Add tags to articles
redis-cli SADD article:1:tags redis set intersection
redis-cli SADD article:2:tags redis set union database
# Find common tags
redis-cli SINTER article:1:tags article:2:tags
# 1) "redis"
# 2) "set"
# All unique tags across both articles
redis-cli SUNION article:1:tags article:2:tags
# 1) "redis"
# 2) "set"
# 3) "intersection"
# 4) "union"
# 5) "database"
Example 4: Using Multiple Sets
# Three user roles: admin, moderator, editor
r.sadd('admin', 'alice', 'bob')
r.sadd('moderator', 'bob', 'charlie')
r.sadd('editor', 'diana', 'bob')
# Users with at least two roles
# Any user appearing in at least two sets = union of all pairs?
# Simpler: intersection of all three?
all_three = r.sinter('admin', 'moderator', 'editor')
print("In all three roles:", list(all_three))
# Output: In all three roles: ['bob']
# Users with only admin role (exclusive)
exclusive_admin = r.sdiff('admin', 'moderator', 'editor')
print("Exclusive admin:", list(exclusive_admin))
# Output: Exclusive admin: ['alice']
Compare Options / When to Choose What
| Operation | When to Use | Performance |
|---|---|---|
SINTER |
Find common members (e.g., mutual followers) | O(N*M) worst-case |
SUNION |
Merge data from multiple sources | O(N) with N total elements |
SDIFF |
Identify unique items in one set only | O(N) of first set |
*STORE commands |
Cache expensive results for reuse | Slower upfront, faster later |
⚠️ Be careful with
SDIFFon large first sets — if the first set has 10 million items and the second has 1 million, the operation is still O(10M). For repeated differences, store the result withSDIFFSTORE.
Redis vs. Alternatives
- Redis Sets – best for real-time, moderate-sized (< 1B total elements) operations on unique values.
- Sorted Sets (ZSET) – if you need ordered results or ranking, use
ZINTERSTORE/ZUNIONSTORE(covered in later lessons). - Python native sets – fine for small data (<10k items) in a single process, but slower for cross-network data sharing.
Troubleshooting & Edge Cases
Mistake 1: Forgetting sets are unordered
result = r.sinter('set_a', 'set_b')
print(result[0]) # Can't rely on order!
Fix: Use SMEMBERS or sort in your application (sorted(result)).
Mistake 2: Passing non-existent keys
r.sinter('missing_set', 'another_set')
# Redis treats missing key as empty set, so result is empty — silent failure.
Fix: Check existence with EXISTS before operations if results surprise you.
Mistake 3: Running SDIFF expecting symmetric difference
SDIFF A B gives A - B. For symmetric difference (items in either but not both), you need (A - B) ∪ (B - A).
Common Errors
- WRONGTYPE Operation against a key holding the wrong kind of value – the key is not a Set. Check with
TYPE key. - Memory blow-up on large unions – if you
SUNIONthree sets of 10M each, Redis holds 30M elements temporarily. UseSUNIONSTOREto write directly to a new key and avoid client‑side memory thrashing. - Network latency – each command is a round trip. Batch operations with
pipeline()for better throughput.
What You Learned & What's Next
You now understand how to find set intersections and unions using Redis's SINTER, SUNION, and SDIFF commands, and how to persist results with *STORE variants. These operations are foundational for building real‑time recommendation engines, audience overlap reports, and access control systems.
In the next lesson, you'll explore Sorted Sets — ordered collections that let you rank leaderboards and handle weighted intersections. You'll learn ZADD, ZRANGE, and weighted union/intersection commands that power gaming and analytics use cases.
Practice recap
Try this exercise on your own: create three sets — students_python, students_js, and students_devops. Add at least 5 members each, with some overlap. Then find: (a) students in all three courses (intersection), (b) students in any of the three (union), (c) students in Python but not in JS (difference). Use SINTERSTORE to save the intersection for reporting.
Common mistakes
- Assuming sets are ordered — always sort results client-side with
sorted(). - Forgetting that a non-existent key is treated as an empty set, which can silently return empty results.
- Using
SDIFFexpecting symmetric difference, but only getting members from the first set. - Running large unions or intersections without storing the result, causing memory spikes client-side.
Variations
- Use
SINTERSTORE,SUNIONSTORE, orSDIFFSTOREto persist the result for later reuse instead of recomputing. - For ordered results, consider
ZINTERSTOREorZUNIONSTOREwith sorted sets and weights. - Combine
SINTERwithSADDin a Lua script to atomically compute and store intersections without client round-trips.
Real-world use cases
- Identify mutual followers or common friend groups between two users in a social network.
- Merge tags from multiple blog posts or articles to generate a unified topic cloud.
- Find users who belong to a beta program but are not yet in the VIP segment for targeted promotions.
Key takeaways
- Redis provides
SINTER,SUNION, andSDIFFfor instant set math at server speed. - Use
*STOREcommands to cache expensive set operations and avoid recomputing. - Non-existent keys are treated as empty sets — always check with
EXISTSfor unexpected empty results. - Sets are unordered; sort results client-side for consistent output.
- For real-time analytics dashboards, Redis set operations outperform SQL JOINs and client-side loops.
- Large union/intersection results should be stored server-side to reduce network and memory pressure.
Keep learning
Related tutorials, quizzes, and articles for this topic.
Discussion
Questions, corrections, and tips help everyone reading this page.
0 comments
Add a comment
No comments yet — start the thread.