/** * Creates a {@link BloomFilter} with the expected number of insertions and a default expected * false positive probability of 3%. * * <p>Note that overflowing a {@code BloomFilter} with significantly more elements than specified, * will result in its saturation, and a sharp deterioration of its false positive probability. * * <p>The constructed {@code BloomFilter} will be serializable if the provided {@code Funnel<T>} * is. * * <p>It is recommended that the funnel be implemented as a Java enum. This has the benefit of * ensuring proper serialization and deserialization, which is important since {@link #equals} * also relies on object identity of funnels. * * @param funnel the funnel of T's that the constructed {@code BloomFilter} will use * @param expectedInsertions the number of expected insertions to the constructed {@code * BloomFilter}; must be positive * @return a {@code BloomFilter} */ public static <T> BloomFilter<T> create(Funnel<? super T> funnel, int expectedInsertions) { return create(funnel, (long) expectedInsertions); }
/** Sanity checking with many combinations of false positive rates and expected insertions */ public void testBasic() { for (double fpr = 0.0000001; fpr < 0.1; fpr *= 10) { for (int expectedInsertions = 1; expectedInsertions <= 10000; expectedInsertions *= 10) { checkSanity(BloomFilter.create(HashTestUtils.BAD_FUNNEL, expectedInsertions, fpr)); } } }
@AndroidIncompatible // OutOfMemoryError public void testLargeNumberOfInsertions() { // We use horrible FPPs here to keep Java from OOM'ing BloomFilter<String> unused = BloomFilter.create(Funnels.unencodedCharsFunnel(), Integer.MAX_VALUE / 2, 0.29); unused = BloomFilter.create(Funnels.unencodedCharsFunnel(), 45L * Integer.MAX_VALUE, 0.99); }
public void testFailureWhenMoreThan255HashFunctionsAreNeeded() { try { int n = 1000; double p = 0.00000000000000000000000000000000000000000000000000000000000000000000000000000001; BloomFilter.create(Funnels.unencodedCharsFunnel(), n, p); fail(); } catch (IllegalArgumentException expected) { } }
public void testEquals_empty() { new EqualsTester() .addEqualityGroup(BloomFilter.create(Funnels.byteArrayFunnel(), 100, 0.01)) .addEqualityGroup(BloomFilter.create(Funnels.byteArrayFunnel(), 100, 0.02)) .addEqualityGroup(BloomFilter.create(Funnels.byteArrayFunnel(), 200, 0.01)) .addEqualityGroup(BloomFilter.create(Funnels.byteArrayFunnel(), 200, 0.02)) .addEqualityGroup(BloomFilter.create(Funnels.unencodedCharsFunnel(), 100, 0.01)) .addEqualityGroup(BloomFilter.create(Funnels.unencodedCharsFunnel(), 100, 0.02)) .addEqualityGroup(BloomFilter.create(Funnels.unencodedCharsFunnel(), 200, 0.01)) .addEqualityGroup(BloomFilter.create(Funnels.unencodedCharsFunnel(), 200, 0.02)) .testEquals(); }
public void testSerializationWithCustomFunnel() { SerializableTester.reserializeAndAssert(BloomFilter.create(new CustomFunnel(), 100)); }
public void testPutReturnValue() { for (int i = 0; i < 10; i++) { BloomFilter<String> bf = BloomFilter.create(Funnels.unencodedCharsFunnel(), 100); for (int j = 0; j < 10; j++) { String value = new Object().toString(); boolean mightContain = bf.mightContain(value); boolean put = bf.put(value); assertTrue(mightContain != put); } } }
public void testCustomSerialization() throws Exception { Funnel<byte[]> funnel = Funnels.byteArrayFunnel(); BloomFilter<byte[]> bf = BloomFilter.create(funnel, 100); for (int i = 0; i < 100; i++) { bf.put(Ints.toByteArray(i)); } ByteArrayOutputStream out = new ByteArrayOutputStream(); bf.writeTo(out); assertEquals(bf, BloomFilter.readFrom(new ByteArrayInputStream(out.toByteArray()), funnel)); }
public void testExpectedFpp() { BloomFilter<Object> bf = BloomFilter.create(HashTestUtils.BAD_FUNNEL, 10, 0.03); double fpp = bf.expectedFpp(); assertEquals(0.0, fpp); // usually completed in less than 200 iterations while (fpp != 1.0) { boolean changed = bf.put(new Object()); double newFpp = bf.expectedFpp(); // if changed, the new fpp is strictly higher, otherwise it is the same assertTrue(changed ? newFpp > fpp : newFpp == fpp); fpp = newFpp; } }
public void testApproximateElementCount() { int numInsertions = 1000; BloomFilter<Integer> bf = BloomFilter.create(Funnels.integerFunnel(), numInsertions); bf.put(-1); for (int i = 0; i < numInsertions; i++) { bf.put(i); } assertApproximateElementCountGuess(bf, numInsertions); }
public void testCollector() { BloomFilter<String> bf1 = BloomFilter.create(Funnels.unencodedCharsFunnel(), 100); bf1.put("1"); bf1.put("2"); assertEquals( bf1, Stream.of("1", "2") .collect(BloomFilter.toBloomFilter(Funnels.unencodedCharsFunnel(), 100))); assertEquals( bf1, Stream.of("2", "1") .collect(BloomFilter.toBloomFilter(Funnels.unencodedCharsFunnel(), 100))); }
public void testNullPointers() { NullPointerTester tester = new NullPointerTester(); tester.testAllPublicInstanceMethods(BloomFilter.create(Funnels.unencodedCharsFunnel(), 100)); tester.testAllPublicStaticMethods(BloomFilter.class); }
public void testCopy() { BloomFilter<String> original = BloomFilter.create(Funnels.unencodedCharsFunnel(), 100); BloomFilter<String> copy = original.copy(); assertNotSame(original, copy); assertEquals(original, copy); }
@AndroidIncompatible // slow public void testBitSize() { double fpp = 0.03; for (int i = 1; i < 10000; i++) { long numBits = BloomFilter.optimalNumOfBits(i, fpp); int arraySize = Ints.checkedCast(LongMath.divide(numBits, 64, RoundingMode.CEILING)); assertEquals( arraySize * Long.SIZE, BloomFilter.create(Funnels.unencodedCharsFunnel(), i, fpp).bitSize()); } }
public void testPutAllWithSelf() { BloomFilter<Integer> bf1 = BloomFilter.create(Funnels.integerFunnel(), 1); try { assertFalse(bf1.isCompatible(bf1)); bf1.putAll(bf1); fail(); } catch (IllegalArgumentException expected) { } }
public void testPutAllDifferentSizes() { BloomFilter<Integer> bf1 = BloomFilter.create(Funnels.integerFunnel(), 1); BloomFilter<Integer> bf2 = BloomFilter.create(Funnels.integerFunnel(), 10); try { assertFalse(bf1.isCompatible(bf2)); bf1.putAll(bf2); fail(); } catch (IllegalArgumentException expected) { } try { assertFalse(bf2.isCompatible(bf1)); bf2.putAll(bf1); fail(); } catch (IllegalArgumentException expected) { } }
public void testEquals() { BloomFilter<String> bf1 = BloomFilter.create(Funnels.unencodedCharsFunnel(), 100); bf1.put("1"); bf1.put("2"); BloomFilter<String> bf2 = BloomFilter.create(Funnels.unencodedCharsFunnel(), 100); bf2.put("1"); bf2.put("2"); new EqualsTester().addEqualityGroup(bf1, bf2).testEquals(); bf2.put("3"); new EqualsTester().addEqualityGroup(bf1).addEqualityGroup(bf2).testEquals(); }
public void testJavaSerialization() { BloomFilter<byte[]> bf = BloomFilter.create(Funnels.byteArrayFunnel(), 100); for (int i = 0; i < 10; i++) { bf.put(Ints.toByteArray(i)); } BloomFilter<byte[]> copy = SerializableTester.reserialize(bf); for (int i = 0; i < 10; i++) { assertTrue(copy.mightContain(Ints.toByteArray(i))); } assertEquals(bf.expectedFpp(), copy.expectedFpp()); SerializableTester.reserializeAndAssert(bf); }
public void testPutAll() { int element1 = 1; int element2 = 2; BloomFilter<Integer> bf1 = BloomFilter.create(Funnels.integerFunnel(), 100); bf1.put(element1); assertTrue(bf1.mightContain(element1)); assertFalse(bf1.mightContain(element2)); BloomFilter<Integer> bf2 = BloomFilter.create(Funnels.integerFunnel(), 100); bf2.put(element2); assertFalse(bf2.mightContain(element1)); assertTrue(bf2.mightContain(element2)); assertTrue(bf1.isCompatible(bf2)); bf1.putAll(bf2); assertTrue(bf1.mightContain(element1)); assertTrue(bf1.mightContain(element2)); assertFalse(bf2.mightContain(element1)); assertTrue(bf2.mightContain(element2)); }