GolangでBucketized Cuckoo Hashingを実装してみた

先日、Cuckoo Hashingの記事を書いたところ、以下のご指摘を頂いたのでBucketized版も実装してみました。

Erlingssonらの論文にも述べられていますが、挿入した要素がテーブルサイズの50%に達すると性能が低下するそうです。 前回も述べましたが、挿入時のハッシュの衝突によって要素の追い出しが起きてしまうためですね。そこで、挿入できる数をひとつでなく複数個にする(本記事ではこれをbucketと呼ぶことにします)ことで、衝突しても用意したbucketの大きさだけそのまま挿入できるようにしたものがBucketized Cuckoo Hashingです。

Fotakisらによるとひとつのbucketに4つの要素まで詰め込めるようにした場合では97%まで空間効率を上げることができるそうです。 この論文中ではBucketized Cuckoo Hashingはd-ary Cuckoo Hashingと呼ばれており、d=4の場合で97%と述べられています。

実装

gist0b30182c97fa91f73174ebcf3baf7645

上記では結果が見やすいようにd=2としています。

ベンチマーク

せっかくなのでbucketized CuckooHashingを通常のCuckooHashingと比較してみます。 ここでは一様乱数で発生させた要素を挿入し、挿入時間を測定します。 測定内容を実環境の問題と合わせて考えるべきですが、実環境の問題はどんなのがあるんでしょうか…

挿入する要素数をテーブルサイズ×bucketサイズで除した値を充填率とし、充填率が大きくなったときに挿入時間がどのように変化するか測定します。
今回は限られたメモリ上でbucketizedするかしないかを決定することを想定し、テーブルサイズとbucketのサイズを以下とします。

[Normal CuckooHashing]
N       int64 = 100000 // テーブルの大きさ

[Bucketized CuckooHashing]
N       int64 = 25000 // テーブルの大きさ
BCKSIZE int   = 4     // bucketのサイズ

ベンチマークコードはGithubにあります。 ベンチマーク結果は以下です。

f:id:cipepser:20170527161928p:plain

全体としてbucketizedしたほうが挿入時間が小さくなっていることがわかります。

References