HyperLogLog to probabilistyczna struktura danych . Zlicza liczbę różnych elementów na liście. Ale w porównaniu z prostym sposobem robienia tego (posiadanie zestawu i dodawanie elementów do zestawu) robi to w przybliżony sposób.
Zanim przyjrzymy się, jak robi to algorytm HyperLogLog, należy zrozumieć, dlaczego jest to potrzebne. Problem z prostym sposobem polega na tym, że zajmuje O(distinct elements)
miejsce. Dlaczego występuje tutaj duża notacja O zamiast tylko odrębnych elementów? Dzieje się tak, ponieważ elementy mogą mieć różne rozmiary. Jeden element może być 1
innym elementem "is this big string"
. Więc jeśli masz ogromną listę (lub ogromny strumień elementów), zajmie to dużo pamięci.
Liczenie probabilistyczne
Jak uzyskać rozsądną ocenę liczby unikalnych elementów? Załóżmy, że masz ciąg o długości m
składającej się z {0, 1}
z równym prawdopodobieństwem. Jakie jest prawdopodobieństwo, że zacznie się od 0, od 2 zer i k zer? Jest 1/2
, 1/4
i 1/2^k
. Oznacza to, że jeśli napotkałeś łańcuch z k
zerami, przejrzałeś w przybliżeniu 2^k
elementy. Więc to jest dobry punkt wyjścia. Mając listę elementów, które są równomiernie rozłożone pomiędzy 0
i 2^k - 1
można policzyć maksymalną liczbę największego prefiksu zer w reprezentacji binarnej i to daje rozsądnego oszacowania.
Problem polega na tym, że założenie o równomiernym rozłożeniu liczb od 0
t 2^k-1
jest zbyt trudne do osiągnięcia (dane, które napotkaliśmy, w większości nie są liczbami, prawie nigdy nie są równomiernie rozłożone i mogą znajdować się między dowolnymi wartościami. Ale używając dobrej funkcji haszującej można założyć, że bity wyjściowe byłyby równomiernie rozłożone, a większość funkcji haszujących ma wyjścia między 0
a 2^k - 1
( SHA1 podaje wartości od 0
do 2^160
). Więc to, co osiągnęliśmy do tej pory, to to, że możemy oszacować liczbę unikalnych elementów z maksymalną licznością k
bitów, przechowując tylko jedną liczbę log(k)
bitów rozmiaru . Wadą jest to, że w naszych szacunkach występują duże rozbieżności. Fajna rzecz, którą prawie stworzyliśmyProbabilistyczny artykuł liczący z 1984 r. (Szacunek jest trochę mądrzejszy, ale wciąż jesteśmy blisko).
LogLog
Zanim przejdziemy dalej, musimy zrozumieć, dlaczego nasze pierwsze oszacowanie nie jest takie świetne. Powodem tego jest to, że jedno przypadkowe wystąpienie elementu o wysokiej częstotliwości z prefiksem 0 może wszystko zepsuć. Jednym ze sposobów na ulepszenie tego jest użycie wielu funkcji skrótu, zliczenie maksimum dla każdej z funkcji skrótu i na koniec uśrednienie ich. To doskonały pomysł, który poprawi oszacowanie, ale papier LogLog zastosował nieco inne podejście (prawdopodobnie dlatego, że haszowanie jest trochę drogie).
Użyli jednego haszyszu, ale podzielili go na dwie części. Jeden nazywa się wiadrem (całkowita liczba wiader to2^x
), a drugi - jest w zasadzie taki sam jak nasz hash. Ciężko mi było zrozumieć, co się dzieje, więc podam przykład. Zakładam, że masz dwa elementy i swoją funkcję skrótu, który podaje wartości formularza 0
do 2^10
produkowanych 2 wartości: 344
a 387
. Zdecydowałeś się mieć 16 wiader. Więc masz:
0101 011000 bucket 5 will store 1
0110 000011 bucket 6 will store 4
Mając więcej koszyków, zmniejszasz wariancję (zużywasz nieco więcej miejsca, ale wciąż jest niewielka). Korzystając z umiejętności matematycznych, byli w stanie obliczyć błąd (który jest 1.3/sqrt(number of buckets)
).
HyperLogLog
HyperLogLog nie wprowadza żadnych nowych pomysłów, ale przede wszystkim wykorzystuje dużo matematyki, aby poprawić poprzednie oszacowanie. Naukowcy odkryli, że jeśli usuniesz 30% największych liczb z koszyków, znacznie poprawisz oszacowanie. Użyli również innego algorytmu do uśredniania liczb. Papier jest ciężki od matematyki.
I chcę zakończyć niedawnym artykułem, który pokazuje ulepszoną wersję algorytmu hyperLogLog (do tej pory nie miałem czasu, aby go w pełni zrozumieć, ale może później poprawię tę odpowiedź).