ข้ามไปยังเนื้อหา

Set Operations

Redis คำนวณ intersection, union, และ difference ระหว่าง Set สองตัวขึ้นไปได้ทั้งหมดบนเซิร์ฟเวอร์ คุณไม่ต้องดึงสมาชิกทั้งหมดมาที่ client แล้วคำนวณเอง

SINTER key [key ...] คืนเฉพาะสมาชิกที่ปรากฏใน ทุก Set ที่ระบุ use case คลาสสิก: เพื่อนร่วมกัน

127.0.0.1:6379> SADD user:1:follows "alice" "bob" "carol" "dave"
(integer) 4
127.0.0.1:6379> SADD user:2:follows "bob" "carol" "eve" "frank"
(integer) 4
127.0.0.1:6379> SINTER user:1:follows user:2:follows
1) "bob"
2) "carol"
SADD user:1:follows "alice" "bob" "carol" "dave"
SADD user:2:follows "bob" "carol" "eve" "frank"
SINTER user:1:follows user:2:follows

SUNION key [key ...] คืนสมาชิกทั้งหมดจาก ทุก Set ที่ระบุ โดย deduplicate ให้ use case: กลุ่มผู้ชมรวมจากหลาย campaign

127.0.0.1:6379> SADD campaign:A "user:1" "user:2" "user:3"
(integer) 3
127.0.0.1:6379> SADD campaign:B "user:2" "user:4" "user:5"
(integer) 3
127.0.0.1:6379> SUNION campaign:A campaign:B
1) "user:1"
2) "user:2"
3) "user:3"
4) "user:4"
5) "user:5"
SADD campaign:A "user:1" "user:2" "user:3"
SADD campaign:B "user:2" "user:4" "user:5"
SUNION campaign:A campaign:B

SDIFF key [key ...] คืนสมาชิกใน Set แรก ที่ไม่ปรากฏใน Set ต่อๆ ไป use case: ค้นหาผู้ใช้ในกลุ่มหนึ่งแต่ไม่อยู่ในอีกกลุ่ม

127.0.0.1:6379> SADD plan:premium "user:1" "user:2" "user:3"
(integer) 3
127.0.0.1:6379> SADD notified:promo "user:2" "user:3"
(integer) 2
127.0.0.1:6379> SDIFF plan:premium notified:promo
1) "user:1"
SADD plan:premium "user:1" "user:2" "user:3"
SADD notified:promo "user:2" "user:3"
SDIFF plan:premium notified:promo

*STORE variants เขียนผลลัพธ์ไปยัง destination key แทนที่จะ return มา destination จะเป็น Set ปกติที่ตรวจสอบได้ภายหลัง

127.0.0.1:6379> SADD group:eng "alice" "bob" "carol"
(integer) 3
127.0.0.1:6379> SADD group:ops "carol" "dave"
(integer) 2
127.0.0.1:6379> SINTERSTORE overlap:eng-ops group:eng group:ops
(integer) 1
127.0.0.1:6379> SMEMBERS overlap:eng-ops
1) "carol"
127.0.0.1:6379> SUNIONSTORE all:staff group:eng group:ops
(integer) 4
127.0.0.1:6379> SMEMBERS all:staff
1) "alice"
2) "bob"
3) "carol"
4) "dave"
SADD group:eng "alice" "bob" "carol"
SADD group:ops "carol" "dave"
SINTERSTORE overlap:eng-ops group:eng group:ops
SMEMBERS overlap:eng-ops
SUNIONSTORE all:staff group:eng group:ops
SMEMBERS all:staff
ตัวเลือกBenefitCost
คำนวณ set algebra บนเซิร์ฟเวอร์ (SINTER/SUNION/SDIFF)ไม่ต้องส่งสมาชิกทั้งหมดมาที่ client เพื่อคำนวณเอง เร็วกว่ามากบน Set ขนาดใหญ่คำสั่งเหล่านี้ block เซิร์ฟเวอร์ระหว่างคำนวณ ถ้า Set ใหญ่มากอาจกระทบ latency ของ client อื่น
*STORE variants (SINTERSTORE เป็นต้น)materialize ผลลัพธ์เป็น key ใหม่ที่อ่านซ้ำได้ทันทีโดยไม่ต้องคำนวณใหม่ผลลัพธ์เป็น snapshot ตอนที่รัน ถ้า Set ต้นทางเปลี่ยนภายหลัง key ผลลัพธ์จะไม่ sync อัตโนมัติ
ใช้ Set แทน SQL JOIN สำหรับความสัมพันธ์แบบง่ายหลีกเลี่ยง JOIN ที่ช้าบนตารางใหญ่เหมาะกับความสัมพันธ์แบบ many-to-many ธรรมดาเท่านั้น ไม่รองรับ query ที่ซับซ้อนแบบ relational
  • เรียก SINTER/SUNION/SDIFF ซ้ำๆ ในทุก request แทนที่จะ cache ผล — ถ้าผลลัพธ์เปลี่ยนไม่บ่อย ควรใช้ *STORE variant เก็บผลไว้ใน key แล้วตั้ง TTL แทนการคำนวณใหม่ทุกครั้ง
  • ลืมว่า SDIFF สนใจลำดับของ key ที่ส่งเข้าไปSDIFF A B กับ SDIFF B A ให้ผลลัพธ์ต่างกัน เพราะ set แรกคือฐานที่ใช้ลบสมาชิกออก สลับลำดับผิดจะได้ผลตรงข้ามที่ไม่ได้ตั้งใจ
  • ใช้ *STORE variant กับ key ปลายทางที่มีข้อมูลอยู่แล้วโดยไม่ตั้งใจ — คำสั่งเหล่านี้ overwrite destination key ทั้งหมด ถ้า key นั้นถูกใช้เก็บข้อมูลอื่นอยู่ ข้อมูลเดิมจะหายไปทันที

💡 ตัวอย่างจากของจริง

ระบบแนะนำเพื่อนร่วมกัน (mutual friends) — แพลตฟอร์มโซเชียลใช้ SINTER ระหว่าง follower set ของผู้ใช้สองคนเพื่อหาเพื่อนร่วมกันแบบ real-time โดยไม่ต้อง query relational database ที่มี JOIN หนักๆ

การรวมกลุ่มผู้ชม campaign การตลาด — ทีม marketing ใช้ SUNION/SINTERSTORE รวมหรือกรอง audience segment จากหลาย campaign บนเซิร์ฟเวอร์ ก่อนส่งไปยัง notification pipeline

คำสั่งใดคืนสมาชิกที่มีอยู่ใน SET ทั้งหมดที่ระบุ?
SDIFF key1 key2 คืนอะไร?
SINTERSTORE destination key1 key2 มีผลอย่างไร?
SUNION ข้าม Set สองตัวที่มีสมาชิกซ้ำกัน จะมีสมาชิกนั้นกี่สำเนา?