Set Operations
Set algebra บนเซิร์ฟเวอร์
หัวข้อที่มีชื่อว่า “Set algebra บนเซิร์ฟเวอร์”Redis คำนวณ intersection, union, และ difference ระหว่าง Set สองตัวขึ้นไปได้ทั้งหมดบนเซิร์ฟเวอร์ คุณไม่ต้องดึงสมาชิกทั้งหมดมาที่ client แล้วคำนวณเอง
SINTER — intersection
หัวข้อที่มีชื่อว่า “SINTER — intersection”SINTER key [key ...] คืนเฉพาะสมาชิกที่ปรากฏใน ทุก Set ที่ระบุ use case คลาสสิก: เพื่อนร่วมกัน
127.0.0.1:6379> SADD user:1:follows "alice" "bob" "carol" "dave"(integer) 4127.0.0.1:6379> SADD user:2:follows "bob" "carol" "eve" "frank"(integer) 4127.0.0.1:6379> SINTER user:1:follows user:2:follows1) "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:followsSUNION — union
หัวข้อที่มีชื่อว่า “SUNION — union”SUNION key [key ...] คืนสมาชิกทั้งหมดจาก ทุก Set ที่ระบุ โดย deduplicate ให้ use case: กลุ่มผู้ชมรวมจากหลาย campaign
127.0.0.1:6379> SADD campaign:A "user:1" "user:2" "user:3"(integer) 3127.0.0.1:6379> SADD campaign:B "user:2" "user:4" "user:5"(integer) 3127.0.0.1:6379> SUNION campaign:A campaign:B1) "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:BSDIFF — difference
หัวข้อที่มีชื่อว่า “SDIFF — difference”SDIFF key [key ...] คืนสมาชิกใน Set แรก ที่ไม่ปรากฏใน Set ต่อๆ ไป use case: ค้นหาผู้ใช้ในกลุ่มหนึ่งแต่ไม่อยู่ในอีกกลุ่ม
127.0.0.1:6379> SADD plan:premium "user:1" "user:2" "user:3"(integer) 3127.0.0.1:6379> SADD notified:promo "user:2" "user:3"(integer) 2127.0.0.1:6379> SDIFF plan:premium notified:promo1) "user:1"SADD plan:premium "user:1" "user:2" "user:3"
SADD notified:promo "user:2" "user:3"
SDIFF plan:premium notified:promoSINTERSTORE, SUNIONSTORE, SDIFFSTORE
หัวข้อที่มีชื่อว่า “SINTERSTORE, SUNIONSTORE, SDIFFSTORE”*STORE variants เขียนผลลัพธ์ไปยัง destination key แทนที่จะ return มา destination จะเป็น Set ปกติที่ตรวจสอบได้ภายหลัง
127.0.0.1:6379> SADD group:eng "alice" "bob" "carol"(integer) 3127.0.0.1:6379> SADD group:ops "carol" "dave"(integer) 2127.0.0.1:6379> SINTERSTORE overlap:eng-ops group:eng group:ops(integer) 1127.0.0.1:6379> SMEMBERS overlap:eng-ops1) "carol"127.0.0.1:6379> SUNIONSTORE all:staff group:eng group:ops(integer) 4127.0.0.1:6379> SMEMBERS all:staff1) "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ข้อแลกเปลี่ยน
หัวข้อที่มีชื่อว่า “ข้อแลกเปลี่ยน”| ตัวเลือก | Benefit | Cost |
|---|---|---|
คำนวณ 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 ผล — ถ้าผลลัพธ์เปลี่ยนไม่บ่อย ควรใช้*STOREvariant เก็บผลไว้ใน key แล้วตั้ง TTL แทนการคำนวณใหม่ทุกครั้ง - ลืมว่า
SDIFFสนใจลำดับของ key ที่ส่งเข้าไป —SDIFF A BกับSDIFF B Aให้ผลลัพธ์ต่างกัน เพราะ set แรกคือฐานที่ใช้ลบสมาชิกออก สลับลำดับผิดจะได้ผลตรงข้ามที่ไม่ได้ตั้งใจ - ใช้
*STOREvariant กับ 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