PostgresQ-ൽ HyperLogLog ഉപയോഗിച്ച് വീഡിയോ ഹീറ്റ്മാപ്പുകൾ നിർമ്മിക്കാം

കാഴ്ചക്കാർ എവിടെ വെച്ചാണ് വീഡിയോ കാണുന്നത് നിർത്തുന്നത് എന്ന് എഡിറ്റർമാർക്ക് കൃത്യമായി കാണിച്ചുകൊടുക്കാൻ നിങ്ങൾ ആഗ്രഹിക്കുന്നു.

ഇതിനായി നിങ്ങൾക്ക് ഒരു ഹീറ്റ്മാപ്പ് (heatmap) ആവശ്യമാണ്. വീഡിയോയുടെ ഓരോ സെക്കൻഡിലും എത്ര തനതായ (unique) കാഴ്ചക്കാർ ഉണ്ടെന്ന് ഈ ഹീറ്റ്മാപ്പ് കാണിക്കുന്നു.

TrendVidStream-ൽ ഞങ്ങൾ ദിവസവും 40 ദശലക്ഷം ഇവന്റുകൾ പ്രോസസ്സ് ചെയ്യുന്നു. ഞങ്ങൾ ലളിതമായ ഒരു സ്റ്റാക്ക് ആണ് ഉപയോഗിക്കുന്നത്: PHP 8.4, Postgres.

പ്രശ്നം കാർഡിനാലിറ്റി (cardinality) ആണ്. ഓരോ സെക്കൻഡിലും എത്ര തനതായ കാഴ്ചക്കാരുണ്ടെന്ന് എണ്ണുന്നത് പ്രയാസകരമാണ്.

ലളിതമായ രീതി:

  • ഒരു റോ (raw) ഇവന്റ്സ് ടേബിൾ ഉപയോഗിക്കുക.
  • COUNT(DISTINCT viewer_hash) റൺ ചെയ്യുക.
  • വീഡിയോയും ടൈം ബക്കറ്റും (time bucket) അനുസരിച്ച് ഗ്രൂപ്പ് ചെയ്യുക.

ഇത് പെട്ടെന്ന് പരാജയപ്പെട്ടു. 90 ദിവസത്തെ ഡാറ്റയ്ക്ക് 3.6 ബില്യൺ വരികൾ ആവശ്യമാണ്. ക്വറികൾക്ക് 9 സെക്കൻഡ് സമയം എടുത്തു. കൂടാതെ, യൂണിക് കൗണ്ടുകൾ റോൾ അപ്പ് (roll up) ചെയ്യാൻ കഴിയില്ല. "ഒരു മണിക്കൂറിലെ യൂണിക്സ്" കൂട്ടിയാൽ "ഒരു ദിവസത്തെ യൂണിക്സ്" ലഭിക്കില്ല, കാരണം ഒരേ വ്യക്തി രണ്ട് സമയത്തും വരാം.

പരിഹാരം: HyperLogLog (HLL).

HLL ഒരു ഡാറ്റാസെറ്റിന്റെ ചെറിയൊരു "സ്കെച്ച്" (sketch) നിർമ്മിക്കുന്നു. എത്ര ദശലക്ഷം ആളുകൾ കണ്ടാലും ഇത് ഏകദേശം 10 KB മാത്രമാണ് വലിപ്പം.

എന്തുകൊണ്ടാണ് ഹീറ്റ്മാപ്പുകൾക്ക് HLL അനുയോജ്യമാകുന്നത്:

  • സ്ഥിരമായ വലിപ്പം (Fixed size): ഇത് ചെറുതായി തന്നെ തുടരുന്നു.
  • മെർജ് ചെയ്യാവുന്നത് (Mergeable): ഒരു ആഗോള കൗണ്ട് ലഭിക്കാൻ നിങ്ങൾക്ക് രണ്ട് സ്കെച്ചുകൾ യോജിപ്പിക്കാം (union). ഇത് റോൾ അപ്പ് പ്രശ്നം പരിഹരിക്കുന്നു.

ഞങ്ങളുടെ നടപ്പിലാക്കൽ:

ഞങ്ങൾ postgresql-hll എക്സ്റ്റൻഷൻ ആണ് ഉപയോഗിക്കുന്നത്. ഞങ്ങൾ രണ്ട് ടേബിളുകൾ ഉപയോഗിക്കുന്നു.

  1. ഒരു സ്റ്റേജിംഗ് ടേബിൾ (staging table): PHP റോ ഹാർട്ട്ബീറ്റുകൾ (raw heartbeats) എഴുതുന്ന ഒരു അപ്പെൻഡ്-ഒൺലി (append-only) ടേബിൾ. എഴുത്ത് വേഗത്തിൽ നടക്കാൻ ഞങ്ങൾ ഇവിടെ ഇൻഡക്സുകൾ ഉപയോഗിക്കുന്നില്ല.
  2. ഒരു സ്കെച്ച് ടേബിൾ (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% വരെ പിശക് (error) ഞങ്ങൾ കാണുന്നു. ഒരു ഹീറ്റ്മാപ്പിനെ സംബന്ധിച്ചിടത്തോളം ഇത് തികച്ചും അനുയോജ്യമാണ്.

പഠിച്ച പാഠങ്ങൾ:

  • ഡാറ്റാബേസിനുള്ളിൽ തന്നെ ഹാഷ് (Hash) ചെയ്യുക. നിങ്ങളുടെ ആപ്പിൽ ഹാഷ് ചെയ്യരുത്.
  • അപ്‌ഡേറ്റുകൾ ബാച്ച് (Batch) ചെയ്യുക. ഓരോ വരിയായി സ്കെച്ചുകൾ അപ്‌ഡേറ്റ് ചെയ്യരുത്, അല്ലെങ്കിൽ അത് റൈറ്റ് ഹോട്ട്‌സ്‌പോട്ടുകൾ (write hotspots) സൃഷ്ടിക്കും.
  • ഹാഷുകൾക്കായി ഒരു ഡെയ്‌ലി സാൾട്ട് (daily salt) ഉപയോഗിക്കുക. ഇത് സ്വകാര്യത സംരക്ഷിക്കുകയും നിങ്ങളുടെ ഡെയ്‌ലി സ്കെച്ചുകൾ വൃത്തിയായി സൂക്ഷിക്കുകയും ചെയ്യുന്നു.

COUNT(DISTINCT) കാരണം നിങ്ങളുടെ ഡാഷ്‌ബോർഡ് പതുക്കെയാണ് പ്രവർത്തിക്കുന്നതെങ്കിൽ, നിങ്ങൾക്ക് ഒരു വലിയ ഡാറ്റാ വെയർഹൗസ് ആവശ്യമില്ല. നിങ്ങൾക്ക് വേണ്ടത് HLL ആണ്.

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