/** * Copyright (C) 2009-2013 FoundationDB, LLC * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ package com.foundationdb.util; import org.junit.Test; import java.util.ArrayList; import java.util.List; import java.util.Random; import static org.junit.Assert.assertTrue; public class BloomFilterTest { @Test public void test() { for (double errorRate : ERROR_RATES) { for (int count : COUNTS) { test("dense longs", errorRate, count, denseLongs(0, count), denseLongs(count, 2 * count)); test("sparse longs", errorRate, count, sparseLongs(0, count), sparseLongs(count, 2 * count)); test("patterned strings", errorRate, count, patternedStrings(0, count), patternedStrings(count, 2 * count)); test("random strings", errorRate, count, randomStrings(0, count), randomStrings(count, 2 * count)); } } } private void test(String label, double errorRate, int count, List keys, List missingKeys) { BloomFilter filter = new BloomFilter(count, errorRate); for (Object key : keys) { filter.add(key.hashCode()); } // Check that all keys are found for (Object key : keys) { assertTrue(filter.maybePresent(key.hashCode())); } // Check false positives for missing keys int falsePositives = 0; for (Object missingKey : missingKeys) { if (filter.maybePresent(missingKey.hashCode())) { falsePositives++; } } double actualErrorRate = ((double) falsePositives) / count; double maxAcceptableErrorRate = errorRate * 10; assertTrue(actualErrorRate <= maxAcceptableErrorRate); } @SuppressWarnings("unchecked") private List denseLongs(int start, int end) { List keys = new ArrayList(end - start); for (long i = start; i < end; i++) { keys.add(i); } return keys; } @SuppressWarnings("unchecked") private List sparseLongs(int start, int end) { List keys = new ArrayList(end - start); for (long i = start; i < end; i++) { long key = (((long) random.nextInt()) << 32) | i; keys.add(key); } return keys; } @SuppressWarnings("unchecked") private List patternedStrings(int start, int end) { List keys = new ArrayList(end - start); for (long i = start; i < end; i++) { String key = String.format("img%09d.jpg", i); keys.add(key); } return keys; } @SuppressWarnings("unchecked") private List randomStrings(int start, int end) { List keys = new ArrayList(end - start); for (long i = start; i < end; i++) { long key = (((long) random.nextInt()) << 32) | i; keys.add(Long.toString(key)); } return keys; } private static final Random random = new Random(419); private static final double[] ERROR_RATES = { 0.10d, 0.1d, 0.01d, 0.001d, 0.0001d }; private static final int[] COUNTS = { 100, 1000, 10000, 100000 }; }