Processing math: 100%

6.07.2015

HyperLogLog Implementation in Redis, pt.3

Redis: HyperLogLog の実装について その3

 

前回は sparse 表現のバイナリについて中身をざっと見た。

今回は HyperLogLog の目的である、カーディナリティを求める処理 pfcount についてその実装を確かめてみる。

 

カウントのコア部分の処理は hllCount 関数に記述されている。

 

カウントの求め方

論文によれば、カーディナリティの期待値 E は以下のように求められる。

  • レジスタの個数を m とする。Redis の場合 m=214=16384
  • このとき E=αmm2mj=12M(j)
  • ここで αm=(m0(log2(2+u1+u))mdu)1

    Redis の場合、これは αm0.7213(1+1.079m)10.7213 で近似される。
  • また、M(j)j番目のレジスタの値である。

 

具体的な例

これまで見てきたように、Redis の HyperLogLog 型に "A", "B", "C" という 3つの値を追加すると、レジスタの状態は以下のようになる。

  • index:4477 -> 3 (C)
  • index:12352 -> 1 (A)
  • index:12964 -> 3 (B)
  • 上記以外の index -> 0

この例で実際に E を求めてみる。

  • 20=1,21=0.5,23=0.125 であるから mj=12M(j)=1(m3)+0.51+0.1252=16381.75
  • したがって E=αmm2mj=12M(j)0.721316384216381.7511819.40

実際のカーディナリティは 3 なので、大きなズレがあるように見える。

期待値の補正

このように、HyperLogLog は小さいカーディナリティに対して大きな誤差が出るという性質がある。
この問題を解決するため、Redis では一旦期待値を算出した後で、以下のルールに従ってその値を補正している。

  • i) E<2.5m=40960 かつ 値が 0 であるレジスタが存在する場合

    以下の式 (Redis のコメントには「LINEARCOUNTING アルゴリズム」と書かれている) によって期待値を計算し直す。値が 0 であるレジスタの個数を z として E:=mlog(mz)

    上記の具体例では、z=163843=16381 なので E:=mlog(mz)=16384log(1638416381)3.0003


    正しいカーディナリティ 3 を得ることができた。

  • ii) i)に該当せず E<72000 の場合
    以下の多項式バイアスを適用して期待値を調整している。これは m=214 の場合に限り適用可能。 bias=5.91191018E41.42531012E3+1.2940107E25.2921103E+83.3216E:=EEbias100
  • iii) その他の場合は補正なし

こうして得られた値 E を 64ビット非負整数に変換したものが、HyperLogLog型のカウントとして得られる値である。

 

Related Posts

0 件のコメント:

コメントを投稿