PostgresQ میں HyperLogLog کے ذریعے ویڈیو ہیٹ میپس بنانا
آپ ایڈیٹرز کو بالکل یہ دکھانا چاہتے ہیں کہ ناظرین ویڈیو کہاں دیکھنا چھوڑ دیتے ہیں۔
اس کے لیے، آپ کو ایک ہیٹ میپ (heatmap) کی ضرورت ہے۔ یہ ہیٹ میپ ویڈیو کے ہر سیکنڈ کے لیے منفرد ناظرین (unique viewers) کو ظاہر کرتا ہے۔
TrendVidStream میں، ہم روزانہ 40 ملین ایونٹس پروسیس کرتے ہیں۔ ہم ایک سادہ اسٹیک استعمال کرتے ہیں: PHP 8.4 اور Postgres۔
مسئلہ کارڈنالٹی (cardinality) کا ہے۔ فی سیکنڈ منفرد ناظرین کی گنتی کرنا مشکل ہے۔
سادہ طریقہ:
- ایک خام ایونٹس ٹیبل (raw events table) استعمال کریں۔
COUNT(DISTINCT viewer_hash)چلائیں۔- ویڈیو اور ٹائم بکٹ (time bucket) کے لحاظ سے گروپ کریں۔
یہ طریقہ جلد ہی ناکام ہو گیا۔ 90 دنوں کے ڈیٹا کے لیے، آپ کو 3.6 بلین روز (rows) کی ضرورت ہوتی ہے۔ کوئریز میں 9 سیکنڈ لگتے تھے۔ اس کے علاوہ، منفرد گنتی کو رول اپ (roll up) نہیں کیا جا سکتا۔ آپ "فی گھنٹہ منفرد" (uniques per hour) کو جمع کر کے "فی دن منفرد" (uniques per day) حاصل نہیں کر سکتے کیونکہ وہی شخص دونوں میں موجود ہو سکتا ہے۔
حل: HyperLogLog (HLL)۔
HLL ڈیٹا سیٹ کا ایک چھوٹا سا "اسکیچ" (sketch) تیار کرتا ہے۔ یہ بہت چھوٹا ہوتا ہے، تقریباً 10 KB، اس سے قطع نظر کہ لاکھوں میں کتنے لوگ دیکھ رہے ہیں۔
HLL ہیٹ میپس کے لیے کیوں کارآمد ہے:
- مقررہ سائز: یہ چھوٹا ہی رہتا ہے۔
- مرج ایبل (Mergeable): آپ عالمی گنتی حاصل کرنے کے لیے دو اسکیچز کو یونین (union) کر سکتے ہیں۔ یہ رول اپ کے مسئلے کو حل کرتا ہے۔
ہماری عملی شکل (Implementation):
ہم postgresql-hll ایکسٹینشن استعمال کرتے ہیں۔ ہم دو ٹیبلز استعمال کرتے ہیں۔
- ایک اسٹیجنگ ٹیبل (staging table): ایک ایسی ٹیبل جس میں صرف ڈیٹا شامل کیا جاتا ہے (append-only) جہاں PHP خام ہارٹ بیٹس (raw heartbeats) لکھتا ہے۔ ہم رائٹس (writes) کو تیز رکھنے کے لیے یہاں انڈیکس (indexes) استعمال نہیں کرتے۔
- ایک اسکیچ ٹیبل (sketch table): یہ HLL ڈیٹا کو محفوظ کرتا ہے۔
ہم اسٹیجنگ سے اسکیچ ٹیبل میں ڈیٹا منتقل کرنے کے لیے ایک کرون جاب (cron job) استعمال کرتے ہیں۔ ہم یہ کمانڈ استعمال کرتے ہیں:
INSERT INTO video_heatmap (...)
SELECT ..., hll_add_agg(hll_hash_text(viewer_hash), 14, 5)
FROM beacon_staging
GROUP BY ...
ON CONFLICT (...)
DO UPDATE SET viewers = video_heatmap.viewers || EXCLUDED.viewers;
"||" آپریٹر نئے ڈیٹا کو موجودہ اسکیچ میں ضم (merge) کر دیتا ہے۔
نتائج:
- کوئری کی رفتار: ہماری ہیٹ میپ کوئریز 15 سے 40 ms لیتی ہیں۔ پرانے طریقے میں 9 سیکنڈ لگتے تھے۔
- اسٹوریج: ہمارا 90 روزہ ڈیٹا سیٹ 40 GB ہے۔ پرانے طریقے میں یہ 1.2 TB لیتا۔
- درستگی: ہمیں تقریباً 0.6% سے 1.4% تک کی غلطی نظر آتی ہے۔ ہیٹ میپ کے لیے، یہ بہترین ہے۔
سیکھے گئے اسباق:
- ڈیٹا بیس کے اندر ہی ہیش (Hash) کریں۔ اپنی ایپ میں ہیش نہ کریں۔
- اپنے اپ ڈیٹس کو بیچ (batch) میں کریں۔ اسکیچز کو ایک وقت میں ایک رو (row) کے حساب سے اپ ڈیٹ نہ کریں ورنہ آپ رائٹ ہاٹ اسپاٹس (write hotspots) پیدا کر دیں گے۔
- ہیشز کے لیے روزانہ سالٹ (salt) استعمال کریں۔ یہ رازداری کی حفاظت کرتا ہے اور آپ کے روزانہ کے اسکیچز کو صاف رکھتا ہے۔
اگر آپ کا ڈیش بورڈ COUNT(DISTINCT) کی وجہ سے سست ہے، تو آپ کو کسی بڑے ڈیٹا ویئر ہاؤس (data warehouse) کی ضرورت نہیں ہے۔ آپ کو HLL کی ضرورت ہے۔
