Bloom Filters: the false positive rate (analysis)

On the previous page we looked at behaviour of the false positive rate of our Java Bloom filter implementation. Ultimately, this behaviour is a combination of various factors involved: not only the "theoretical" behaviour assuming truly random selection of objects and perfect hash codes, but to a small extent, the actual distribution of possible object values and the quality of our hash function. So I think that looking at some "real life" data is important. However, for completeness, I will look briefly here at how we can approximate the behaviour of the Bloom filter from a more mathematical point of view.

It turns out that the exact mathematics of how Bloom filters perform is rather complex. Anyone with a deep interest in this subject is encouraged to consult Bose et al (2007), On the false-positive rate of Bloom filters. For our purposes, we will make do with two simple approximations, which turn out to be good enough in most cases.

Mathematical approximation of the false positive rate

There are two simple mathematical approximations to the false positive rate. The logic in each case is similar and both approximations give similar results, differing subtly in the assumptions they make.

The first approximation appears in Bloom's original 1970 paper. Consider a Bloom filter with k hash codes and an underlying bit set of m bits. This means that each time we add an item, we expect to set k bits, or proportionally, k/m of the bits. So after the first item is inserted, we assume the proportion of bits still not set is 1-k/m. After the second item is inserted, we assume that proportion will be (1-k/m)(1-k/m). After the third item, (1-k/m)(1-k/m)(1-k/m) etc, so that after n items are inserted, we expect the proportion of bits still to be clear to be (1-k/m)n.

This is an oversimplification on two grounds. It ignores the fact that very occasionally two or more of the k bits set for a given item will coincide and we won't actually change the state of k bits. (Clearly, this chance becomes more miniscule as m is much greater than k, which will generally be the case.) Perhaps more significantly, it assumes that bits are set independently of one another, whereas in reality, the more bits that are set, the more chance of a bit "colliding" with one already set and not altering the proportion of bits set. But for Bloom filters that aren't "too full", it's a good enough approximation. Then, given a random item that we happen to know isn't actually in the set, the chance that our Bloom filter will erroneously report that it is present is equal to the likelihood that all corresponding k bits for that item are set. In other words, if (1-k/m)n is the proportion of bits that are clear, then for a each individual bit to be set it must be in the remaining 1-(1-k/m)n proportion of bits. Thus the overall likelihood of all k bits being set is assumed to be this proportion multiplied by itself k times:

approx f. p. rate = (1-(1-k/m)n)k

The second approximation— and the one that appears to be most common in descriptions of Bloom filters— follows a slightly different line of logic but arrives at a similar result.

If you enjoy this Java programming article, please share with friends and colleagues. Follow the author on Twitter for the latest news and rants.

Editorial page content written by Neil Coffey. Copyright © Javamex UK 2021. All rights reserved.