PostgresQ లో HyperLogLog తో వీడియో హీట్‌మ్యాప్‌లను నిర్మించడం

వీక్షకులు వీడియోను ఎక్కడ చూడటం ఆపేస్తున్నారో ఎడిటర్లకు ఖచ్చితంగా చూపించాలనుకుంటారు.

దీని కోసం, మీకు ఒక హీట్‌మ్యాప్ (heatmap) అవసరం. ఈ హీట్‌మ్యాప్ వీడియోలోని ప్రతి సెకనుకు ఎంతమంది విభిన్న వీక్షకులు (unique viewers) ఉన్నారో చూపిస్తుంది.

TrendVidStreamలో, మేము ప్రతిరోజూ 40 మిలియన్ ఈవెంట్‌లను ప్రాసెస్ చేస్తాము. మేము PHP 8.4 మరియు Postgres వంటి సరళమైన స్టాక్‌ను ఉపయోగిస్తాము.

సమస్య కార్డినాలిటీ (cardinality). ప్రతి సెకనుకు విభిన్న వీక్షకులను లెక్కించడం కష్టమైన పని.

సాధారణ పద్ధతి (The naive way):

  • ఒక రా (raw) ఈవెంట్స్ టేబుల్‌ను ఉపయోగించడం.
  • 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) చేయవచ్చు. ఇది రోల్ అప్ సమస్యను పరిష్కరిస్తుంది.

మా అమలు (Our Implementation):

మేము postgresql-hll ఎక్స్‌టెన్షన్‌ను ఉపయోగిస్తాము. మేము రెండు టేబుల్స్‌ను ఉపయోగిస్తాము.

  1. స్టేజింగ్ టేబుల్ (A staging table): ఇది ఒక అపెండ్-ఓన్లీ (append-only) టేబుల్, ఇక్కడ PHP రా (raw) హార్ట్‌బీట్‌లను రాస్తుంది. రైట్ ఆపరేషన్లు వేగంగా ఉండటానికి మేము ఇక్కడ ఇండెక్స్‌లను ఉపయోగించము.
  2. స్కెచ్ టేబుల్ (A 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) చేస్తుంది.

ఫలితాలు (The Results):

  • క్వెరీ వేగం: మా హీట్‌మ్యాప్ క్వెరీలకు 15 నుండి 40 ms పడుతుంది. పాత పద్ధతిలో 9 సెకన్లు పట్టేది.
  • స్టోరేజ్: మా 90 రోజుల డేటాసెట్ 40 GB మాత్రమే. పాత పద్ధతిలో ఇది 1.2 TB అయ్యేది.
  • ఖచ్చితత్వం: మేము సుమారు 0.6% నుండి 1.4% లోపు ఎర్రర్‌ను చూస్తున్నాము. ఒక హీట్‌మ్యాప్‌కు ఇది సరిగ్గా సరిపోతుంది.

నేర్చుకున్న పాఠాలు (Lessons learned):

  • డేటాబేస్ లోపలే హాష్ (Hash) చేయండి. మీ యాప్‌లో హాష్ చేయవద్దు.
  • అప్‌డేట్‌లను బ్యాచ్‌లుగా చేయండి. స్కెచ్‌లను ఒక్కో రో (row) చొప్పున అప్‌డేట్ చేయవద్దు, లేకపోతే రైట్ హాట్‌స్పాట్‌లు (write hotspots) ఏర్పడతాయి.
  • హాష్‌ల కోసం రోజువారీ సాల్ట్ (salt) ఉపయోగించండి. ఇది గోప్యతను కాపాడుతుంది మరియు మీ రోజువారీ స్కెచ్‌లను క్లీన్‌గా ఉంచుతుంది.

మీ డాష్‌బోర్డ్ COUNT(DISTINCT) వల్ల నెమ్మదిగా ఉంటే, మీకు భారీ డేటా వేర్‌హౌస్ అవసరం లేదు. మీకు HLL అవసరం.

Source: https://dev.to/ahmet_gedik778845/building-per-second-video-heatmap-analytics-with-hyperloglog-in-postgres-2p22