HyperLogLog は確率的データ構造です。リスト内の個別の要素の数をカウントします。しかし、それを行う簡単な方法 (セットを持ち、セットに要素を追加する) と比較すると、これはおおよその方法で行われます。
HyperLogLog アルゴリズムがこれをどのように行うかを見る前に、なぜそれが必要なのかを理解する必要があります。O(distinct elements)
簡単な方法の問題は、スペースを消費することです。ここに、個別の要素ではなく、大きな O 表記があるのはなぜですか? これは、要素のサイズが異なる可能性があるためです。1 つの要素を1
別の要素にすることができます"is this big string"
。したがって、巨大なリスト (または要素の巨大なストリーム) がある場合、多くのメモリが必要になります。
確率的カウント
一意の要素の数を合理的に見積もるにはどうすればよいでしょうか? 等しい確率m
で構成される長さの文字列があると仮定します。{0, 1}
0、2 つのゼロ、k のゼロから始まる確率は? です1/2
、1/4
そして1/2^k
。これは、k
ゼロを含む文字列に遭遇した場合、おおよそ2^k
の要素を調べたことを意味します。したがって、これは良い出発点です。均等に分散された要素のリストがあり0
、2^k - 1
バイナリ表現でゼロの最大プレフィックスの最大数を数えることができ、これにより合理的な見積もりが得られます。
0
問題は、 tから数値が均等に分散されているという仮定2^k-1
を達成するのが難しすぎることです (私たちが遭遇したデータは、ほとんどが数値ではなく、均等に分散されることはほとんどなく、任意の値の間に存在する可能性があります。しかし、優れたハッシュ関数を使用すると、次のように仮定できます。出力ビットは均等に分散され、ほとんどのハッシュ関数は と の間の出力を持ちます( SHA10
はとの間の値を返します). したがって、これまでに達成したことは、ビットの最大カーディナリティを持つ一意の要素の数を、格納するだけで推定できることです。サイズビットの 1 つの数. マイナス面は、見積もりに大きなばらつきがあることです. 私たちがほぼ作成したクールなもの2^k - 1
0
2^160
k
log(k)
1984 年の確率論的計数論文 (見積もりの方が少しスマートですが、それでも近いです)。
ログログ
先に進む前に、最初の見積もりがそれほど大きくない理由を理解する必要があります。その背後にある理由は、高頻度の 0 プレフィックス要素が 1 回ランダムに発生すると、すべてが台無しになる可能性があるためです。それを改善する1つの方法は、多くのハッシュ関数を使用し、各ハッシュ関数の最大値を数え、最終的にそれらを平均化することです. これは優れたアイデアであり、推定値を改善しますが、LogLog の論文では、わずかに異なるアプローチが使用されました (おそらく、ハッシングはコストがかかるためです)。
彼らは 1 つのハッシュを使用しましたが、それを 2 つの部分に分割しました。1 つはバケット (バケットの総数は2^x
) と呼ばれ、もう 1 つは基本的にハッシュと同じです。何が起こっているのかわかりにくかったので、例を挙げます。0
2 つの要素と、生成された 2 つの値に値を与えるハッシュ関数があると仮定します2^10
:344
と387
. 16 個のバケットを持つことにしました。だからあなたは持っています:
0101 011000 bucket 5 will store 1
0110 000011 bucket 6 will store 4
バケットを増やすと、分散が減少します (使用するスペースがわずかに増えますが、それでも小さいです)。数学のスキルを使用して、エラーを定量化することができました (これは です1.3/sqrt(number of buckets)
)。
ハイパーログログ
HyperLogLogは新しいアイデアを導入するものではありませんが、以前の見積もりを改善するために多くの計算を使用します。研究者は、バケットから最大数の 30% を削除すると、推定値が大幅に改善されることを発見しました。彼らはまた、数値を平均化するために別のアルゴリズムを使用しました。この論文は数学が重いです。
そして、hyperLogLog アルゴリズムの改良版を示す最近の論文で締めくくりたいと思います(これまでは完全に理解する時間がありませんでしたが、後でこの回答を改善する予定です)。