Upgrade to Pro — share decks privately, control downloads, hide ads and more …

A Redis compatible HLL implementation in Java

A Redis compatible HLL implementation in Java

Okada Haruki

August 02, 2019
Tweet

More Decks by Okada Haruki

Other Decks in Programming

Transcript

  1. Redis 互換なHyperLogLog の Java 実装を作った話 @ocadaruma

  2. HyperLogLog ユニークカウントを高速・省メモリに推定する確 率的データ構造 Redis にも標準で入ってる

  3. 原理の直感的な説明 64bit int を一様ランダムに選んだとき、「左から 数えて1 が最初に立つのがk bit 目」である確率は 1/2^k

  4. 原理の直感的な説明 いいかえると、2^k 個ランダムに選ばないと「左端 の1 がk bit 目」であるような数が現れない つまりあるデータセットの要素を64bit hash にか

    けて「左端の1 のbit 番号」だけ記録すれば、そのデ ータセットのユニークカウントを推定できる もちろんこれだけだと2^k 単位でしか近似できない し精度も悪いので、hash 関数をm 個使ってその平 均を取る、とか色々やる 実際は別々のhash 関数を用意するんじゃなくて もっと頭のいい方法でやる
  5. HyperLogLog on Redis $ for i in `seq 1000`; redis­cli

    PFADD key $i > /dev/null $ redis­cli PFCOUNT key (integer) 1001 $ for i in `seq 1000`; redis­cli PFADD key $i > /dev/null $ redis­cli PFCOUNT key (integer) 1001 $ for i in `seq 100`; redis­cli PFADD foo a$i > /dev/null $ redis­cli PFCOUNT foo (integer) 99 $ redis­cli PFMERGE merged key foo OK $ redis­cli PFCOUNT merged (integer) 1103
  6. 利用例 page やドメイン単位でUU 数をリアルタイムにレポ ートするシステム

  7. PFMERGE は比較的遅い Redis 上で重い操作はあんまりしたくない

  8. HyperLogLog の内部表現 普通に内部表現をGET できる 公式doc にもちゃんと書いてある https://redis.io/commands/pfcount redis­cli> PFADD key

    elem1 elem2 (integer) 1 redis­cli> GET key "HYLL\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x80i\xe1\x80N\ The HyperLogLog, being a Redis string,can be retrieved with GET and restored with SET. “ “
  9. Java 側で操作できれば便利では? PFMERGE みたいな重い操作をRedis 上でやらず、 アプリケーション側に内部表現を持ってきて、 Java 上でやれると便利

  10. pfutil https://github.com/ocadaruma/pfutil Redis v4 とv5 ではアルゴリズムがちょっと違う 内部表現は同じ どっちのアルゴリズムにも対応

  11. 例 $ amm > import $ivy.`com.mayreh:pfutil:0.1.1` > import com.mayreh.pfutil.v4.HllV4 >

    val hll = HllV4.newBuilder().build() > (1 to 1000).foreach(i => hll.pfAdd(s"$i".getBytes)) > hll.pfCount() res4: Long = 1001L > val hll2 = HllV4.newBuilder().build() > (1 to 100).foreach(i => hll2.pfAdd(s"a$i".getBytes)) > hll2.pfCount() res7: Long = 99L > hll.pfMerge(hll2).pfcount() res8: Long = 1103L
  12. まとめ 確率的データ構造面白くて便利!