BloomFilterImpl(int numHashFunctions, long numBits) { this(new BitArray(numBits), numHashFunctions); }
@Override public double expectedFpp() { return Math.pow((double) bits.cardinality() / bits.bitSize(), numHashFunctions); }
@Override public boolean equals(Object other) { if (other == this) { return true; } if (other == null || !(other instanceof BloomFilterImpl)) { return false; } BloomFilterImpl that = (BloomFilterImpl) other; return this.numHashFunctions == that.numHashFunctions && this.bits.equals(that.bits); }
@Override public boolean putBinary(byte[] item) { int h1 = Murmur3_x86_32.hashUnsafeBytes(item, Platform.BYTE_ARRAY_OFFSET, item.length, 0); int h2 = Murmur3_x86_32.hashUnsafeBytes(item, Platform.BYTE_ARRAY_OFFSET, item.length, h1); long bitSize = bits.bitSize(); boolean bitsChanged = false; for (int i = 1; i <= numHashFunctions; i++) { int combinedHash = h1 + (i * h2); // Flip all the bits if it's negative (guaranteed positive number) if (combinedHash < 0) { combinedHash = ~combinedHash; } bitsChanged |= bits.set(combinedHash % bitSize); } return bitsChanged; }
@Override public boolean mightContainLong(long item) { int h1 = Murmur3_x86_32.hashLong(item, 0); int h2 = Murmur3_x86_32.hashLong(item, h1); long bitSize = bits.bitSize(); for (int i = 1; i <= numHashFunctions; i++) { int combinedHash = h1 + (i * h2); // Flip all the bits if it's negative (guaranteed positive number) if (combinedHash < 0) { combinedHash = ~combinedHash; } if (!bits.get(combinedHash % bitSize)) { return false; } } return true; }
private void readFrom0(InputStream in) throws IOException { DataInputStream dis = new DataInputStream(in); int version = dis.readInt(); if (version != Version.V1.getVersionNumber()) { throw new IOException("Unexpected Bloom filter version number (" + version + ")"); } this.numHashFunctions = dis.readInt(); this.bits = BitArray.readFrom(dis); }
/** Returns true if the bit changed value. */ boolean set(long index) { if (!get(index)) { data[(int) (index >>> 6)] |= (1L << index); bitCount++; return true; } return false; }
@Override public int hashCode() { return bits.hashCode() * 31 + numHashFunctions; }
@Override public long bitSize() { return bits.bitSize(); }
BitArray(long numBits) { this(new long[numWords(numBits)]); }
@Override public BloomFilter mergeInPlace(BloomFilter other) throws IncompatibleMergeException { // Duplicates the logic of `isCompatible` here to provide better error message. if (other == null) { throw new IncompatibleMergeException("Cannot merge null bloom filter"); } if (!(other instanceof BloomFilterImpl)) { throw new IncompatibleMergeException( "Cannot merge bloom filter of class " + other.getClass().getName() ); } BloomFilterImpl that = (BloomFilterImpl) other; if (this.bitSize() != that.bitSize()) { throw new IncompatibleMergeException("Cannot merge bloom filters with different bit size"); } if (this.numHashFunctions != that.numHashFunctions) { throw new IncompatibleMergeException( "Cannot merge bloom filters with different number of hash functions" ); } this.bits.putAll(that.bits); return this; }
@Override public boolean putBinary(byte[] item) { int h1 = Murmur3_x86_32.hashUnsafeBytes(item, Platform.BYTE_ARRAY_OFFSET, item.length, 0); int h2 = Murmur3_x86_32.hashUnsafeBytes(item, Platform.BYTE_ARRAY_OFFSET, item.length, h1); long bitSize = bits.bitSize(); boolean bitsChanged = false; for (int i = 1; i <= numHashFunctions; i++) { int combinedHash = h1 + (i * h2); // Flip all the bits if it's negative (guaranteed positive number) if (combinedHash < 0) { combinedHash = ~combinedHash; } bitsChanged |= bits.set(combinedHash % bitSize); } return bitsChanged; }
@Override public boolean mightContainBinary(byte[] item) { int h1 = Murmur3_x86_32.hashUnsafeBytes(item, Platform.BYTE_ARRAY_OFFSET, item.length, 0); int h2 = Murmur3_x86_32.hashUnsafeBytes(item, Platform.BYTE_ARRAY_OFFSET, item.length, h1); long bitSize = bits.bitSize(); for (int i = 1; i <= numHashFunctions; i++) { int combinedHash = h1 + (i * h2); // Flip all the bits if it's negative (guaranteed positive number) if (combinedHash < 0) { combinedHash = ~combinedHash; } if (!bits.get(combinedHash % bitSize)) { return false; } } return true; }
private void readFrom0(InputStream in) throws IOException { DataInputStream dis = new DataInputStream(in); int version = dis.readInt(); if (version != Version.V1.getVersionNumber()) { throw new IOException("Unexpected Bloom filter version number (" + version + ")"); } this.numHashFunctions = dis.readInt(); this.bits = BitArray.readFrom(dis); }
/** Returns true if the bit changed value. */ boolean set(long index) { if (!get(index)) { data[(int) (index >>> 6)] |= (1L << index); bitCount++; return true; } return false; }
@Override public int hashCode() { return bits.hashCode() * 31 + numHashFunctions; }
@Override public long bitSize() { return bits.bitSize(); }
BitArray(long numBits) { this(new long[numWords(numBits)]); }
@Override public BloomFilter mergeInPlace(BloomFilter other) throws IncompatibleMergeException { // Duplicates the logic of `isCompatible` here to provide better error message. if (other == null) { throw new IncompatibleMergeException("Cannot merge null bloom filter"); } if (!(other instanceof BloomFilterImpl)) { throw new IncompatibleMergeException( "Cannot merge bloom filter of class " + other.getClass().getName() ); } BloomFilterImpl that = (BloomFilterImpl) other; if (this.bitSize() != that.bitSize()) { throw new IncompatibleMergeException("Cannot merge bloom filters with different bit size"); } if (this.numHashFunctions != that.numHashFunctions) { throw new IncompatibleMergeException( "Cannot merge bloom filters with different number of hash functions" ); } this.bits.putAll(that.bits); return this; }
@Override public boolean putBinary(byte[] item) { int h1 = Murmur3_x86_32.hashUnsafeBytes(item, Platform.BYTE_ARRAY_OFFSET, item.length, 0); int h2 = Murmur3_x86_32.hashUnsafeBytes(item, Platform.BYTE_ARRAY_OFFSET, item.length, h1); long bitSize = bits.bitSize(); boolean bitsChanged = false; for (int i = 1; i <= numHashFunctions; i++) { int combinedHash = h1 + (i * h2); // Flip all the bits if it's negative (guaranteed positive number) if (combinedHash < 0) { combinedHash = ~combinedHash; } bitsChanged |= bits.set(combinedHash % bitSize); } return bitsChanged; }