├── .gitignore ├── .travis.yml ├── LICENSE ├── README.md ├── pom.xml └── src ├── main └── java │ └── com │ └── github │ └── wxisme │ └── bloomfilter │ ├── bitset │ ├── BaseBitSet.java │ ├── JavaBitSet.java │ └── RedisBitSet.java │ └── common │ ├── BloomFilter.java │ └── MessageDigestUtils.java └── test └── java └── com └── github └── wxisme └── bloomfilter └── bitset ├── JavaBitSetTest.java ├── RedisBitSetTest.java ├── YourBitSet.java └── YourBitSetTest.java /.gitignore: -------------------------------------------------------------------------------- 1 | 2 | .apt_generated 3 | .classpath 4 | .factorypath 5 | .project 6 | .settings 7 | .springBeans 8 | 9 | .idea 10 | *.iws 11 | *.iml 12 | *.ipr 13 | 14 | target/ 15 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: java 2 | jdk: 3 | - oraclejdk8 4 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | GNU LESSER GENERAL PUBLIC LICENSE 2 | Version 3, 29 June 2007 3 | 4 | Copyright (C) 2007 Free Software Foundation, Inc. 5 | Everyone is permitted to copy and distribute verbatim copies 6 | of this license document, but changing it is not allowed. 7 | 8 | 9 | This version of the GNU Lesser General Public License incorporates 10 | the terms and conditions of version 3 of the GNU General Public 11 | License, supplemented by the additional permissions listed below. 12 | 13 | 0. Additional Definitions. 14 | 15 | As used herein, "this License" refers to version 3 of the GNU Lesser 16 | General Public License, and the "GNU GPL" refers to version 3 of the GNU 17 | General Public License. 18 | 19 | "The Library" refers to a covered work governed by this License, 20 | other than an Application or a Combined Work as defined below. 21 | 22 | An "Application" is any work that makes use of an interface provided 23 | by the Library, but which is not otherwise based on the Library. 24 | Defining a subclass of a class defined by the Library is deemed a mode 25 | of using an interface provided by the Library. 26 | 27 | A "Combined Work" is a work produced by combining or linking an 28 | Application with the Library. The particular version of the Library 29 | with which the Combined Work was made is also called the "Linked 30 | Version". 31 | 32 | The "Minimal Corresponding Source" for a Combined Work means the 33 | Corresponding Source for the Combined Work, excluding any source code 34 | for portions of the Combined Work that, considered in isolation, are 35 | based on the Application, and not on the Linked Version. 36 | 37 | The "Corresponding Application Code" for a Combined Work means the 38 | object code and/or source code for the Application, including any data 39 | and utility programs needed for reproducing the Combined Work from the 40 | Application, but excluding the System Libraries of the Combined Work. 41 | 42 | 1. Exception to Section 3 of the GNU GPL. 43 | 44 | You may convey a covered work under sections 3 and 4 of this License 45 | without being bound by section 3 of the GNU GPL. 46 | 47 | 2. Conveying Modified Versions. 48 | 49 | If you modify a copy of the Library, and, in your modifications, a 50 | facility refers to a function or data to be supplied by an Application 51 | that uses the facility (other than as an argument passed when the 52 | facility is invoked), then you may convey a copy of the modified 53 | version: 54 | 55 | a) under this License, provided that you make a good faith effort to 56 | ensure that, in the event an Application does not supply the 57 | function or data, the facility still operates, and performs 58 | whatever part of its purpose remains meaningful, or 59 | 60 | b) under the GNU GPL, with none of the additional permissions of 61 | this License applicable to that copy. 62 | 63 | 3. Object Code Incorporating Material from Library Header Files. 64 | 65 | The object code form of an Application may incorporate material from 66 | a header file that is part of the Library. You may convey such object 67 | code under terms of your choice, provided that, if the incorporated 68 | material is not limited to numerical parameters, data structure 69 | layouts and accessors, or small macros, inline functions and templates 70 | (ten or fewer lines in length), you do both of the following: 71 | 72 | a) Give prominent notice with each copy of the object code that the 73 | Library is used in it and that the Library and its use are 74 | covered by this License. 75 | 76 | b) Accompany the object code with a copy of the GNU GPL and this license 77 | document. 78 | 79 | 4. Combined Works. 80 | 81 | You may convey a Combined Work under terms of your choice that, 82 | taken together, effectively do not restrict modification of the 83 | portions of the Library contained in the Combined Work and reverse 84 | engineering for debugging such modifications, if you also do each of 85 | the following: 86 | 87 | a) Give prominent notice with each copy of the Combined Work that 88 | the Library is used in it and that the Library and its use are 89 | covered by this License. 90 | 91 | b) Accompany the Combined Work with a copy of the GNU GPL and this license 92 | document. 93 | 94 | c) For a Combined Work that displays copyright notices during 95 | execution, include the copyright notice for the Library among 96 | these notices, as well as a reference directing the user to the 97 | copies of the GNU GPL and this license document. 98 | 99 | d) Do one of the following: 100 | 101 | 0) Convey the Minimal Corresponding Source under the terms of this 102 | License, and the Corresponding Application Code in a form 103 | suitable for, and under terms that permit, the user to 104 | recombine or relink the Application with a modified version of 105 | the Linked Version to produce a modified Combined Work, in the 106 | manner specified by section 6 of the GNU GPL for conveying 107 | Corresponding Source. 108 | 109 | 1) Use a suitable shared library mechanism for linking with the 110 | Library. A suitable mechanism is one that (a) uses at run time 111 | a copy of the Library already present on the user's computer 112 | system, and (b) will operate properly with a modified version 113 | of the Library that is interface-compatible with the Linked 114 | Version. 115 | 116 | e) Provide Installation Information, but only if you would otherwise 117 | be required to provide such information under section 6 of the 118 | GNU GPL, and only to the extent that such information is 119 | necessary to install and execute a modified version of the 120 | Combined Work produced by recombining or relinking the 121 | Application with a modified version of the Linked Version. (If 122 | you use option 4d0, the Installation Information must accompany 123 | the Minimal Corresponding Source and Corresponding Application 124 | Code. If you use option 4d1, you must provide the Installation 125 | Information in the manner specified by section 6 of the GNU GPL 126 | for conveying Corresponding Source.) 127 | 128 | 5. Combined Libraries. 129 | 130 | You may place library facilities that are a work based on the 131 | Library side by side in a single library together with other library 132 | facilities that are not Applications and are not covered by this 133 | License, and convey such a combined library under terms of your 134 | choice, if you do both of the following: 135 | 136 | a) Accompany the combined library with a copy of the same work based 137 | on the Library, uncombined with any other library facilities, 138 | conveyed under the terms of this License. 139 | 140 | b) Give prominent notice with the combined library that part of it 141 | is a work based on the Library, and explaining where to find the 142 | accompanying uncombined form of the same work. 143 | 144 | 6. Revised Versions of the GNU Lesser General Public License. 145 | 146 | The Free Software Foundation may publish revised and/or new versions 147 | of the GNU Lesser General Public License from time to time. Such new 148 | versions will be similar in spirit to the present version, but may 149 | differ in detail to address new problems or concerns. 150 | 151 | Each version is given a distinguishing version number. If the 152 | Library as you received it specifies that a certain numbered version 153 | of the GNU Lesser General Public License "or any later version" 154 | applies to it, you have the option of following the terms and 155 | conditions either of that published version or of any later version 156 | published by the Free Software Foundation. If the Library as you 157 | received it does not specify a version number of the GNU Lesser 158 | General Public License, you may choose any version of the GNU Lesser 159 | General Public License ever published by the Free Software Foundation. 160 | 161 | If the Library as you received it specifies that a proxy can decide 162 | whether future versions of the GNU Lesser General Public License shall 163 | apply, that proxy's public statement of acceptance of any version is 164 | permanent authorization for you to choose that version for the 165 | Library. 166 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # bloomfilter 2 | [![Build Status](https://travis-ci.org/wxisme/bloomfilter.svg?branch=master)](https://travis-ci.org/wxisme/bloomfilter) ![GitHub release](https://img.shields.io/github/release/wxisme/bloomfilter.svg) ![GitHub license](https://img.shields.io/badge/license-LGPL--3.0-brightgreen.svg) 3 | 4 | An empty Bloom filter is a bit array of m bits, all set to 0. There must also be hashNumber different hash functions defined, each of which maps or hashes some set element to one of the m array positions, generating a uniform random distribution. Typically, hashNumber is a constant, much smaller than m, which is proportional to the number of elements to be added; the precise choice of hashNumber and the constant of proportionality of m are determined by the intended false positive probability of the filter.
5 | If you are not familiar with it, you can refer to [Wikipedia's detailed analysis](https://en.wikipedia.org/wiki/Bloom_filter).
6 | If you use python, you can refer to the [bloomfilter written in python](https://github.com/wxisme/py-bloomfilter) 7 | 8 | ## Overview 9 | 10 | This project implements bloomfilter and can select and extend different BitSets or other storage methods. For example, BitSet supports `Java` and `Redis`. It can also be applied to scenarios where various data levels and different false positive probability are required.
11 | 12 | Release Log:
13 | bloomfilter version 1.0.0 Released
14 | 15 | [Download](https://github.com/wxisme/bloomfilter/releases) source code and binary jar package on the [release page](https://github.com/wxisme/bloomfilter/releases).
16 | 17 | 18 | ## Quick Start 19 | 20 | ### ~~Download & Install~~ 21 | 22 | This is not necessary now. The dependency uploaded to the maven central repository.
23 | 24 | ``` 25 | git clone https://github.com/wxisme/bloomfilter.git 26 | 27 | cd bloomfilter 28 | 29 | mvn clean install 30 | ``` 31 | 32 | You can also download source code or binary jar package on the [release page](https://github.com/wxisme/bloomfilter/releases) directly.
33 | 34 | ### Add maven dependency 35 | 36 | ```xml 37 | 38 | 39 | com.github.wxisme 40 | bloomfilter 41 | 1.0.0 42 | 43 | 44 | ``` 45 | 46 | ### Test 47 | 48 | ```java 49 | public class JavaBitSetTest { 50 | 51 | public static void main(String[] args) { 52 | //(falsePositiveProbability, expectedNumberOfElements) 53 | BloomFilter filter = new BloomFilter(0.0001, 10000); 54 | filter.bind(new JavaBitSet()); 55 | 56 | filter.add("filter"); 57 | System.out.println(filter.contains("filter")); 58 | System.out.println(filter.contains("bloom")); 59 | filter.add("bitset"); 60 | filter.add("redis"); 61 | System.out.println(filter.contains("bitset")); 62 | System.out.println(filter.contains("redis")); 63 | System.out.println(filter.contains("mysql")); 64 | System.out.println(filter.contains("linux")); 65 | System.out.println(filter.count()); 66 | System.out.println(filter.isEmpty()); 67 | filter.clear(); 68 | System.out.println(filter.isEmpty()); 69 | System.out.println(filter.contains("filter")); 70 | 71 | } 72 | 73 | } 74 | ``` 75 | Expected test result is :
76 | ``` 77 | true 78 | false 79 | true 80 | true 81 | false 82 | false 83 | 3 84 | false 85 | true 86 | false 87 | ``` 88 | 89 | ### Redis and other extensions 90 | 91 | 92 | #### Redis 93 | 94 | You can easily use bloomfilter on redis,here is a simple example: 95 | 96 | ```java 97 | public class RedisBitSetTest { 98 | 99 | public static void main(String[] args) { 100 | 101 | //Don't forget auth password, you better use the configured redis client connection. 102 | //It should be noted that bloomfilter is not responsible for closing and returning redis connection resources. 103 | 104 | //(falsePositiveProbability, expectedNumberOfElements) 105 | BloomFilter filter = new BloomFilter(0.0001, 10000); 106 | Jedis jedis = new Jedis("127.0.0.1", 6379); 107 | jedis.auth("1234"); 108 | filter.bind(new RedisBitSet(jedis, "bloomfilter:key:name")); 109 | 110 | //if you have a redis cluster 111 | //Set nodes = new HashSet<>(); 112 | //nodes.add(new HostAndPort("127.0.0.1", 6379)); 113 | 114 | //filter.bind(new RedisBitSet(new JedisCluster(nodes), "bloomfilter:key:name")); 115 | 116 | //you can also use jedispool 117 | //JedisPool jedisPool = new JedisPool("127.0.0.1", 6379); 118 | //Jedis jedis = jedisPool.getResource(); 119 | //filter.bind(new RedisBitSet(jedis, "bloomfilter:key:name")); 120 | 121 | filter.add("filter"); 122 | System.out.println(filter.contains("filter")); 123 | System.out.println(filter.contains("bloom")); 124 | filter.add("bitset"); 125 | filter.add("redis"); 126 | System.out.println(filter.contains("bitset")); 127 | System.out.println(filter.contains("redis")); 128 | System.out.println(filter.contains("mysql")); 129 | System.out.println(filter.contains("linux")); 130 | System.out.println(filter.count()); 131 | System.out.println(filter.isEmpty()); 132 | filter.clear(); 133 | System.out.println(filter.isEmpty()); 134 | System.out.println(filter.contains("filter")); 135 | } 136 | } 137 | ``` 138 | Don't forget auth password, you better use the configured redis client connection. It should be noted that bloomfilter is not responsible for closing and returning redis connection resources.
139 | If you are not familiar with redis, you can refer to the following hyperlink:
140 | https://redis.io
141 | https://github.com/xetorthio/jedis
142 | 143 | Test result is :
144 | ``` 145 | true 146 | false 147 | true 148 | true 149 | false 150 | false 151 | 3 152 | false 153 | true 154 | false 155 | ``` 156 | #### Extensions 157 | 158 | If you want to use your own data structure, you can directly implement the `BaseBitSet` interface.
159 | Example:
160 | 161 | ```java 162 | public class YourBitSet implements BaseBitSet { 163 | 164 | private int[] data;//boolean array 165 | 166 | public YourBitSet(int size) { 167 | data = new int[size]; 168 | } 169 | 170 | @Override 171 | public void set(int bitIndex) { 172 | data[bitIndex] = 1; 173 | } 174 | 175 | @Override 176 | public void set(int bitIndex, boolean value) { 177 | if (value) 178 | data[bitIndex] = 1; 179 | else data[bitIndex] = 0; 180 | } 181 | 182 | @Override 183 | public boolean get(int bitIndex) { 184 | return data[bitIndex] == 1; 185 | } 186 | 187 | @Override 188 | public void clear(int bitIndex) { 189 | data[bitIndex] = 0; 190 | } 191 | 192 | @Override 193 | public void clear() { 194 | Arrays.fill(data, 0); 195 | } 196 | 197 | @Override 198 | public long size() { 199 | long size = 0; 200 | for (int d : data) 201 | if (d == 1) 202 | size++; 203 | return size; 204 | } 205 | 206 | @Override 207 | public boolean isEmpty() { 208 | return size() <= 0; 209 | } 210 | } 211 | ``` 212 | Test:
213 | ```java 214 | public class YourBitSetTest { 215 | 216 | public static void main(String[] args) { 217 | //(falsePositiveProbability, expectedNumberOfElements) 218 | BloomFilter filter = new BloomFilter(0.0001, 10000); 219 | filter.bind(new YourBitSet(1000000)); 220 | 221 | filter.add("filter"); 222 | System.out.println(filter.contains("filter")); 223 | System.out.println(filter.contains("bloom")); 224 | filter.add("bitset"); 225 | filter.add("redis"); 226 | System.out.println(filter.contains("bitset")); 227 | System.out.println(filter.contains("redis")); 228 | System.out.println(filter.contains("mysql")); 229 | System.out.println(filter.contains("linux")); 230 | System.out.println(filter.count()); 231 | System.out.println(filter.isEmpty()); 232 | filter.clear(); 233 | System.out.println(filter.isEmpty()); 234 | System.out.println(filter.contains("filter")); 235 | 236 | } 237 | 238 | } 239 | ``` 240 | Test result is :
241 | ``` 242 | true 243 | false 244 | true 245 | true 246 | false 247 | false 248 | 3 249 | false 250 | true 251 | false 252 | ``` 253 | 254 | #### Welcome to submit your extension code or put any question issues on github. 255 | 256 | ### License 257 | 258 | Bloomfilter is released under the [GNU Lesser General Public License v3.0](http://www.gnu.org/licenses/).
259 | You can just use maven to import dependency package or use your own compiled jar package.
260 | You may copy this code directly into your project if you leave the LGPL-comment in place and reference the following hyperlink:
261 | https://github.com/MagnusS/Java-BloomFilter
262 | https://github.com/wxisme/bloomfilter
263 | -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 4.0.0 6 | 7 | com.github.wxisme 8 | bloomfilter 9 | 1.0.0 10 | 11 | 12 | org.sonatype.oss 13 | oss-parent 14 | 7 15 | 16 | 17 | 18 | 19 | 20 | org.apache.maven.plugins 21 | maven-compiler-plugin 22 | 23 | 1.8 24 | 1.8 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | redis.clients 33 | jedis 34 | 2.8.1 35 | 36 | 37 | 38 | 39 | 40 | GNU Lesser General Public License Version 3 41 | http://www.gnu.org/licenses/lgpl.txt 42 | repo 43 | 44 | 45 | 46 | master 47 | https://github.com/wxisme/bloomfilter.git 48 | scm:git:https://github.com/wxisme/bloomfilter.git 49 | scm:git:https://github.com/wxisme/bloomfilter.git 50 | 51 | 52 | 53 | Wang Xu 54 | wangxucoop@126.com 55 | wxisme 56 | 57 | 58 | 59 | -------------------------------------------------------------------------------- /src/main/java/com/github/wxisme/bloomfilter/bitset/BaseBitSet.java: -------------------------------------------------------------------------------- 1 | /** 2 | * This program is free software: you can redistribute it and/or modify 3 | * it under the terms of the GNU Lesser General Public License as published by 4 | * the Free Software Foundation, either version 3 of the License, or 5 | * (at your option) any later version. 6 | * 7 | * This program is distributed in the hope that it will be useful, 8 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 9 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 10 | * GNU Lesser General Public License for more details. 11 | * 12 | * You should have received a copy of the GNU Lesser General Public License 13 | * along with this program. If not, see . 14 | */ 15 | 16 | package com.github.wxisme.bloomfilter.bitset; 17 | 18 | /** 19 | * Base bit set interface. If you want to use your own data structure you can implement this interface. 20 | */ 21 | public interface BaseBitSet extends Cloneable, java.io.Serializable { 22 | 23 | /** 24 | * Set a single bit in the Bloom filter, value default is true. 25 | * 26 | * @param bitIndex bit index. 27 | */ 28 | public void set(int bitIndex); 29 | 30 | /** 31 | * Set a single bit in the Bloom filter, value is true or false. 32 | * 33 | * @param bitIndex bit index. 34 | * @param value value true or false. 35 | */ 36 | public void set(int bitIndex, boolean value); 37 | 38 | /** 39 | * Return the bit set used to store the Bloom filter. 40 | * 41 | * @param bitIndex bit index. 42 | * @return the bit set used to store the Bloom filter. 43 | */ 44 | public boolean get(int bitIndex); 45 | 46 | /** 47 | * Clear the bit set on the index, so the bit set value is false on index. 48 | * 49 | * @param bitIndex bit index. 50 | */ 51 | public void clear(int bitIndex); 52 | 53 | /** 54 | * Clear the bit set, so the bit set value is all false. 55 | */ 56 | public void clear(); 57 | 58 | /** 59 | * Returns the number of bits in the Bloom filter. 60 | * 61 | * @return the number of bits in the Bloom filter. 62 | */ 63 | public long size(); 64 | 65 | /** 66 | * Returns is the bit set empty, bit set is empty means no any elements added to bit set. 67 | * 68 | * @return is the bit set empty. 69 | */ 70 | public boolean isEmpty(); 71 | } 72 | -------------------------------------------------------------------------------- /src/main/java/com/github/wxisme/bloomfilter/bitset/JavaBitSet.java: -------------------------------------------------------------------------------- 1 | /** 2 | * This program is free software: you can redistribute it and/or modify 3 | * it under the terms of the GNU Lesser General Public License as published by 4 | * the Free Software Foundation, either version 3 of the License, or 5 | * (at your option) any later version. 6 | * 7 | * This program is distributed in the hope that it will be useful, 8 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 9 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 10 | * GNU Lesser General Public License for more details. 11 | * 12 | * You should have received a copy of the GNU Lesser General Public License 13 | * along with this program. If not, see . 14 | */ 15 | 16 | package com.github.wxisme.bloomfilter.bitset; 17 | 18 | import java.util.BitSet; 19 | 20 | /** 21 | * Implement bloom filter on native java bitset. 22 | */ 23 | public class JavaBitSet implements BaseBitSet { 24 | 25 | private BitSet bitSet; 26 | 27 | public JavaBitSet() { 28 | this.bitSet = new BitSet(); 29 | } 30 | 31 | public JavaBitSet(BitSet bitSet) { 32 | if (bitSet == null) { 33 | this.bitSet = new BitSet(); 34 | } else { 35 | this.bitSet = bitSet; 36 | } 37 | } 38 | 39 | public void set(int bitIndex) { 40 | this.bitSet.set(bitIndex); 41 | } 42 | 43 | public void set(int bitIndex, boolean value) { 44 | this.bitSet.set(bitIndex, value); 45 | } 46 | 47 | public boolean get(int bitIndex) { 48 | return this.bitSet.get(bitIndex); 49 | } 50 | 51 | public void clear(int bitIndex) { 52 | this.bitSet.clear(bitIndex); 53 | } 54 | 55 | public void clear() { 56 | this.bitSet.clear(); 57 | } 58 | 59 | public long size() { 60 | return this.bitSet.size(); 61 | } 62 | 63 | public boolean isEmpty() { 64 | return this.isEmpty(); 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /src/main/java/com/github/wxisme/bloomfilter/bitset/RedisBitSet.java: -------------------------------------------------------------------------------- 1 | /** 2 | * This program is free software: you can redistribute it and/or modify 3 | * it under the terms of the GNU Lesser General Public License as published by 4 | * the Free Software Foundation, either version 3 of the License, or 5 | * (at your option) any later version. 6 | * 7 | * This program is distributed in the hope that it will be useful, 8 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 9 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 10 | * GNU Lesser General Public License for more details. 11 | * 12 | * You should have received a copy of the GNU Lesser General Public License 13 | * along with this program. If not, see . 14 | */ 15 | 16 | package com.github.wxisme.bloomfilter.bitset; 17 | 18 | import redis.clients.jedis.Jedis; 19 | import redis.clients.jedis.JedisCluster; 20 | 21 | /** 22 | * Implement bloom filter on redis bitset. 23 | */ 24 | public class RedisBitSet implements BaseBitSet { 25 | 26 | private JedisCluster jedisCluster; 27 | private Jedis jedis; 28 | private String name; 29 | 30 | private boolean isCluster = true; 31 | 32 | private RedisBitSet() { 33 | } 34 | 35 | /** 36 | * Create a redis bitset. 37 | * @param jedisCluster jedis cluster client. 38 | * @param name the redis bit key name. 39 | */ 40 | public RedisBitSet(JedisCluster jedisCluster, String name) { 41 | this.jedisCluster = jedisCluster; 42 | this.name = name; 43 | this.isCluster = true; 44 | } 45 | 46 | /** 47 | * Create a redis bitset. 48 | * @param jedis jedis client. 49 | * @param name the redis bit key name. 50 | */ 51 | public RedisBitSet(Jedis jedis, String name) { 52 | this.jedis = jedis; 53 | this.name = name; 54 | this.isCluster = false; 55 | } 56 | 57 | 58 | public void set(int bitIndex) { 59 | if (this.isCluster) { 60 | this.jedisCluster.setbit(this.name, bitIndex, true); 61 | } else { 62 | this.jedis.setbit(this.name, bitIndex, true); 63 | } 64 | } 65 | 66 | public void set(int bitIndex, boolean value) { 67 | if (this.isCluster) { 68 | this.jedisCluster.setbit(this.name, bitIndex, value); 69 | } else { 70 | this.jedis.setbit(this.name, bitIndex, value); 71 | } 72 | } 73 | 74 | public boolean get(int bitIndex) { 75 | if (this.isCluster) { 76 | return this.jedisCluster.getbit(this.name, bitIndex); 77 | } else { 78 | return this.jedis.getbit(this.name, bitIndex); 79 | } 80 | } 81 | 82 | public void clear(int bitIndex) { 83 | if (this.isCluster) { 84 | this.jedisCluster.setbit(this.name, bitIndex, false); 85 | } else { 86 | this.jedis.setbit(this.name, bitIndex, false); 87 | } 88 | } 89 | 90 | public void clear() { 91 | if (this.isCluster) { 92 | this.jedisCluster.del(this.name); 93 | } else { 94 | this.jedis.del(this.name); 95 | } 96 | } 97 | 98 | public long size() { 99 | if (this.isCluster) { 100 | return this.jedisCluster.bitcount(this.name); 101 | } else { 102 | return this.jedis.bitcount(this.name); 103 | } 104 | } 105 | 106 | public boolean isEmpty() { 107 | return size() <= 0; 108 | } 109 | } 110 | -------------------------------------------------------------------------------- /src/main/java/com/github/wxisme/bloomfilter/common/BloomFilter.java: -------------------------------------------------------------------------------- 1 | /** 2 | * This program is free software: you can redistribute it and/or modify 3 | * it under the terms of the GNU Lesser General Public License as published by 4 | * the Free Software Foundation, either version 3 of the License, or 5 | * (at your option) any later version. 6 | * 7 | * This program is distributed in the hope that it will be useful, 8 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 9 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 10 | * GNU Lesser General Public License for more details. 11 | * 12 | * You should have received a copy of the GNU Lesser General Public License 13 | * along with this program. If not, see . 14 | */ 15 | 16 | package com.github.wxisme.bloomfilter.common; 17 | 18 | import com.github.wxisme.bloomfilter.bitset.BaseBitSet; 19 | 20 | import java.io.Serializable; 21 | import java.util.Collection; 22 | 23 | /** 24 | * This program refers to the java-bloomfilter,you can get its details form https://github.com/MagnusS/Java-BloomFilter. 25 | * You have any questions about this program please put issues on github to 26 | * https://github.com/wxisme/bloomfilter 27 | * 28 | * @param Element type 29 | */ 30 | public class BloomFilter implements Cloneable, Serializable { 31 | 32 | private BaseBitSet bitSet; 33 | private int bitSetSize; 34 | private double bitsPerElement; 35 | private int expectedNumberOfFilterElements; // expected (maximum) number of elements to be added 36 | private int numberOfAddedElements; // number of elements actually added to the Bloom filter 37 | private int k; // number of hash functions 38 | 39 | 40 | /** 41 | * Bind a bit set for Bloom filter. It can be any data structure that implements the BaseBitSet interface. 42 | * @param bitSet 43 | */ 44 | public void bind(BaseBitSet bitSet) { 45 | this.bitSet = bitSet; 46 | } 47 | 48 | /** 49 | * Constructs an empty Bloom filter. The total length of the Bloom filter will be 50 | * c*n. 51 | * 52 | * @param c is the number of bits used per element. 53 | * @param n is the expected number of elements the filter will contain. 54 | * @param k is the number of hash functions used. 55 | */ 56 | public BloomFilter(double c, int n, int k) { 57 | this.expectedNumberOfFilterElements = n; 58 | this.k = k; 59 | this.bitsPerElement = c; 60 | this.bitSetSize = (int) Math.ceil(c * n); 61 | numberOfAddedElements = 0; 62 | } 63 | 64 | /** 65 | * Constructs an empty Bloom filter. The optimal number of hash functions (k) is estimated from the total size of the Bloom 66 | * and the number of expected elements. 67 | * 68 | * @param bitSetSize defines how many bits should be used in total for the filter. 69 | * @param expectedNumberOElements defines the maximum number of elements the filter is expected to contain. 70 | */ 71 | public BloomFilter(int bitSetSize, int expectedNumberOElements) { 72 | this(bitSetSize / (double) expectedNumberOElements, 73 | expectedNumberOElements, 74 | (int) Math.round((bitSetSize / (double) expectedNumberOElements) * Math.log(2.0))); 75 | } 76 | 77 | /** 78 | * Constructs an empty Bloom filter with a given false positive probability. The number of bits per 79 | * element and the number of hash functions is estimated 80 | * to match the false positive probability. 81 | * 82 | * @param falsePositiveProbability is the desired false positive probability. 83 | * @param expectedNumberOfElements is the expected number of elements in the Bloom filter. 84 | */ 85 | public BloomFilter(double falsePositiveProbability, int expectedNumberOfElements) { 86 | this(Math.ceil(-(Math.log(falsePositiveProbability) / Math.log(2.0))) / Math.log(2.0), // c = k / ln(2) 87 | expectedNumberOfElements, 88 | (int) Math.ceil(-(Math.log(falsePositiveProbability) / Math.log(2.0)))); // k = ceil(-log_2(false prob.)) 89 | } 90 | 91 | /** 92 | * Construct a new Bloom filter based on existing Bloom filter data. 93 | * 94 | * @param bitSetSize defines how many bits should be used for the filter. 95 | * @param expectedNumberOfFilterElements defines the maximum number of elements the filter is expected to contain. 96 | * @param actualNumberOfFilterElements specifies how many elements have been inserted into the filterData BitSet. 97 | * @param filterData a BitSet representing an existing Bloom filter. 98 | */ 99 | public BloomFilter(int bitSetSize, int expectedNumberOfFilterElements, int actualNumberOfFilterElements, BaseBitSet filterData) { 100 | this(bitSetSize, expectedNumberOfFilterElements); 101 | this.bitSet = filterData; 102 | this.numberOfAddedElements = actualNumberOfFilterElements; 103 | } 104 | 105 | 106 | /** 107 | * Compares the contents of two instances to see if they are equal. 108 | * 109 | * @param obj is the object to compare to. 110 | * @return True if the contents of the objects are equal. 111 | */ 112 | @Override 113 | public boolean equals(Object obj) { 114 | if (obj == null) { 115 | return false; 116 | } 117 | if (getClass() != obj.getClass()) { 118 | return false; 119 | } 120 | final BloomFilter other = (BloomFilter) obj; 121 | if (this.expectedNumberOfFilterElements != other.expectedNumberOfFilterElements) { 122 | return false; 123 | } 124 | if (this.k != other.k) { 125 | return false; 126 | } 127 | if (this.bitSetSize != other.bitSetSize) { 128 | return false; 129 | } 130 | if (this.bitSet != other.bitSet && (this.bitSet == null || !this.bitSet.equals(other.bitSet))) { 131 | return false; 132 | } 133 | return true; 134 | } 135 | 136 | /** 137 | * Calculates a hash code for this class. 138 | * 139 | * @return hash code representing the contents of an instance of this class. 140 | */ 141 | @Override 142 | public int hashCode() { 143 | int hash = 7; 144 | hash = 61 * hash + (this.bitSet != null ? this.bitSet.hashCode() : 0); 145 | hash = 61 * hash + this.expectedNumberOfFilterElements; 146 | hash = 61 * hash + this.bitSetSize; 147 | hash = 61 * hash + this.k; 148 | return hash; 149 | } 150 | 151 | 152 | /** 153 | * Calculates the expected probability of false positives based on 154 | * the number of expected filter elements and the size of the Bloom filter. 155 | * 156 | * The value returned by this method is the expected rate of false 157 | * positives, assuming the number of inserted elements equals the number of 158 | * expected elements. If the number of elements in the Bloom filter is less 159 | * than the expected value, the true probability of false positives will be lower. 160 | * 161 | * 162 | * @return expected probability of false positives. 163 | */ 164 | public double expectedFalsePositiveProbability() { 165 | return getFalsePositiveProbability(expectedNumberOfFilterElements); 166 | } 167 | 168 | /** 169 | * Calculate the probability of a false positive given the specified 170 | * number of inserted elements. 171 | * 172 | * @param numberOfElements number of inserted elements. 173 | * @return probability of a false positive. 174 | */ 175 | public double getFalsePositiveProbability(double numberOfElements) { 176 | // (1 - e^(-k * n / m)) ^ k 177 | return Math.pow((1 - Math.exp(-k * (double) numberOfElements 178 | / (double) bitSetSize)), k); 179 | 180 | } 181 | 182 | /** 183 | * Get the current probability of a false positive. The probability is calculated from 184 | * the size of the Bloom filter and the current number of elements added to it. 185 | * 186 | * @return probability of false positives. 187 | */ 188 | public double getFalsePositiveProbability() { 189 | return getFalsePositiveProbability(numberOfAddedElements); 190 | } 191 | 192 | 193 | /** 194 | * Returns the value chosen for K. 195 | * 196 | * K is the optimal number of hash functions based on the size 197 | * of the Bloom filter and the expected number of inserted elements. 198 | * 199 | * @return optimal k. 200 | */ 201 | public int getK() { 202 | return k; 203 | } 204 | 205 | /** 206 | * Sets all bits to false in the Bloom filter. 207 | */ 208 | public void clear() { 209 | bitSet.clear(); 210 | numberOfAddedElements = 0; 211 | } 212 | 213 | /** 214 | * Adds an object to the Bloom filter. The output from the object's 215 | * toString() method is used as input to the hash functions. 216 | * 217 | * @param element is an element to register in the Bloom filter. 218 | */ 219 | public void add(E element) { 220 | add(element.toString().getBytes(MessageDigestUtils.CHARSET)); 221 | } 222 | 223 | /** 224 | * Adds an array of bytes to the Bloom filter. 225 | * 226 | * @param bytes array of bytes to add to the Bloom filter. 227 | */ 228 | public void add(byte[] bytes) { 229 | int[] hashes = MessageDigestUtils.createHashes(bytes, k); 230 | for (int hash : hashes) 231 | bitSet.set(Math.abs(hash % bitSetSize), true); 232 | numberOfAddedElements++; 233 | } 234 | 235 | /** 236 | * Adds all elements from a Collection to the Bloom filter. 237 | * 238 | * @param c Collection of elements. 239 | */ 240 | public void addAll(Collection c) { 241 | for (E element : c) 242 | add(element); 243 | } 244 | 245 | /** 246 | * Returns true if the element could have been inserted into the Bloom filter. 247 | * Use getFalsePositiveProbability() to calculate the probability of this 248 | * being correct. 249 | * 250 | * @param element element to check. 251 | * @return true if the element could have been inserted into the Bloom filter. 252 | */ 253 | public boolean contains(E element) { 254 | return contains(element.toString().getBytes(MessageDigestUtils.CHARSET)); 255 | } 256 | 257 | /** 258 | * Returns true if the array of bytes could have been inserted into the Bloom filter. 259 | * Use getFalsePositiveProbability() to calculate the probability of this 260 | * being correct. 261 | * 262 | * @param bytes array of bytes to check. 263 | * @return true if the array could have been inserted into the Bloom filter. 264 | */ 265 | public boolean contains(byte[] bytes) { 266 | int[] hashes = MessageDigestUtils.createHashes(bytes, k); 267 | for (int hash : hashes) { 268 | if (!bitSet.get(Math.abs(hash % bitSetSize))) { 269 | return false; 270 | } 271 | } 272 | return true; 273 | } 274 | 275 | /** 276 | * Returns true if all the elements of a Collection could have been inserted 277 | * into the Bloom filter. Use getFalsePositiveProbability() to calculate the 278 | * probability of this being correct. 279 | * 280 | * @param c elements to check. 281 | * @return true if all the elements in c could have been inserted into the Bloom filter. 282 | */ 283 | public boolean containsAll(Collection c) { 284 | for (E element : c) 285 | if (!contains(element)) 286 | return false; 287 | return true; 288 | } 289 | 290 | /** 291 | * Read a single bit from the Bloom filter. 292 | * 293 | * @param bit the bit to read. 294 | * @return true if the bit is set, false if it is not. 295 | */ 296 | public boolean getBit(int bit) { 297 | return bitSet.get(bit); 298 | } 299 | 300 | /** 301 | * Set a single bit in the Bloom filter. 302 | * 303 | * @param bit is the bit to set. 304 | * @param value If true, the bit is set. If false, the bit is cleared. 305 | */ 306 | public void setBit(int bit, boolean value) { 307 | bitSet.set(bit, value); 308 | } 309 | 310 | /** 311 | * Return the bit set used to store the Bloom filter. 312 | * 313 | * @return bit set representing the Bloom filter. 314 | */ 315 | public BaseBitSet getBitSet() { 316 | return bitSet; 317 | } 318 | 319 | /** 320 | * Returns the number of bits in the Bloom filter. Use count() to retrieve 321 | * the number of inserted elements. 322 | * 323 | * @return the size of the bitSet used by the Bloom filter. 324 | */ 325 | public int size() { 326 | return this.bitSetSize; 327 | } 328 | 329 | /** 330 | * Returns the number of elements added to the Bloom filter after it 331 | * was constructed or after clear() was called. 332 | * 333 | * @return number of elements added to the Bloom filter. 334 | */ 335 | public int count() { 336 | return this.numberOfAddedElements; 337 | } 338 | 339 | /** 340 | * Returns is the bit set empty, bit set is empty means no any elements added to bloom filter. 341 | * 342 | * @return is the bit set empty 343 | */ 344 | public boolean isEmpty() { 345 | return count() <= 0; 346 | } 347 | 348 | /** 349 | * Returns the expected number of elements to be inserted into the filter. 350 | * This value is the same value as the one passed to the constructor. 351 | * 352 | * @return expected number of elements. 353 | */ 354 | public int getExpectedNumberOfElements() { 355 | return expectedNumberOfFilterElements; 356 | } 357 | 358 | /** 359 | * Get expected number of bits per element when the Bloom filter is full. This value is set by the constructor 360 | * when the Bloom filter is created. See also getBitsPerElement(). 361 | * 362 | * @return expected number of bits per element. 363 | */ 364 | public double getExpectedBitsPerElement() { 365 | return this.bitsPerElement; 366 | } 367 | 368 | /** 369 | * Get actual number of bits per element based on the number of elements that have currently been inserted and the length 370 | * of the Bloom filter. See also getExpectedBitsPerElement(). 371 | * 372 | * @return number of bits per element. 373 | */ 374 | public double getBitsPerElement() { 375 | return this.bitSetSize / (double) numberOfAddedElements; 376 | } 377 | 378 | } -------------------------------------------------------------------------------- /src/main/java/com/github/wxisme/bloomfilter/common/MessageDigestUtils.java: -------------------------------------------------------------------------------- 1 | /** 2 | * This program is free software: you can redistribute it and/or modify 3 | * it under the terms of the GNU Lesser General Public License as published by 4 | * the Free Software Foundation, either version 3 of the License, or 5 | * (at your option) any later version. 6 | * 7 | * This program is distributed in the hope that it will be useful, 8 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 9 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 10 | * GNU Lesser General Public License for more details. 11 | * 12 | * You should have received a copy of the GNU Lesser General Public License 13 | * along with this program. If not, see . 14 | */ 15 | 16 | package com.github.wxisme.bloomfilter.common; 17 | 18 | import java.nio.charset.Charset; 19 | import java.security.MessageDigest; 20 | import java.security.NoSuchAlgorithmException; 21 | 22 | /** 23 | * This program refers to the java-bloomfilter,you can get its details form https://github.com/MagnusS/Java-BloomFilter. 24 | * You have any questions about this program please put issues on github to 25 | * https://github.com/wxisme/bloomfilter 26 | */ 27 | public class MessageDigestUtils { 28 | 29 | private static final String MESSAGE_DIGEST_ALGORITHM_NAME = "MD5";//SHA1,SHA256 30 | public static final Charset CHARSET = Charset.forName("UTF-8"); // encoding used for storing hash values as strings 31 | 32 | 33 | private static final MessageDigest messageDigest; 34 | 35 | static { 36 | MessageDigest tempMessageDigest = null; 37 | try { 38 | tempMessageDigest = MessageDigest.getInstance(MESSAGE_DIGEST_ALGORITHM_NAME); 39 | } catch (NoSuchAlgorithmException e) { 40 | e.printStackTrace(); 41 | } 42 | messageDigest = tempMessageDigest; 43 | } 44 | 45 | /** 46 | * Generates a digest based on the contents of a String. 47 | * 48 | * @param val specifies the input data. 49 | * @param charset specifies the encoding of the input data. 50 | * @return digest as long. 51 | */ 52 | public static int createHash(String val, Charset charset) { 53 | return createHash(val.getBytes(charset)); 54 | } 55 | 56 | /** 57 | * Generates a digest based on the contents of a String. 58 | * 59 | * @param val specifies the input data. The encoding is expected to be UTF-8. 60 | * @return digest as long. 61 | */ 62 | public static int createHash(String val) { 63 | return createHash(val, CHARSET); 64 | } 65 | 66 | /** 67 | * Generates a digest based on the contents of an array of bytes. 68 | * 69 | * @param data specifies input data. 70 | * @return digest as long. 71 | */ 72 | public static int createHash(byte[] data) { 73 | return createHashes(data, 1)[0]; 74 | } 75 | 76 | /** 77 | * Generates digests based on the contents of an array of bytes and splits the result into 4-byte int's and store them in an array. The 78 | * digest function is called until the required number of int's are produced. For each call to digest a salt 79 | * is prepended to the data. The salt is increased by 1 for each call. 80 | * 81 | * @param data specifies input data. 82 | * @param hashes number of hashes/int's to produce. 83 | * @return array of int-sized hashes 84 | */ 85 | public static int[] createHashes(byte[] data, int hashes) { 86 | int[] result = new int[hashes]; 87 | 88 | int k = 0; 89 | byte salt = 0; 90 | while (k < hashes) { 91 | byte[] digest; 92 | synchronized (messageDigest) { 93 | messageDigest.update(salt); 94 | salt++; 95 | digest = messageDigest.digest(data); 96 | } 97 | 98 | for (int i = 0; i < digest.length / 4 && k < hashes; i++) { 99 | int h = 0; 100 | for (int j = (i * 4); j < (i * 4) + 4; j++) { 101 | h <<= 8; 102 | h |= ((int) digest[j]) & 0xFF; 103 | } 104 | result[k] = h; 105 | k++; 106 | } 107 | } 108 | return result; 109 | } 110 | 111 | } 112 | -------------------------------------------------------------------------------- /src/test/java/com/github/wxisme/bloomfilter/bitset/JavaBitSetTest.java: -------------------------------------------------------------------------------- 1 | package com.github.wxisme.bloomfilter.bitset; 2 | 3 | import com.github.wxisme.bloomfilter.common.BloomFilter; 4 | 5 | public class JavaBitSetTest { 6 | 7 | public static void main(String[] args) { 8 | //(falsePositiveProbability, expectedNumberOfElements) 9 | BloomFilter filter = new BloomFilter(0.0001, 10000); 10 | filter.bind(new JavaBitSet()); 11 | 12 | filter.add("filter"); 13 | System.out.println(filter.contains("filter")); 14 | System.out.println(filter.contains("bloom")); 15 | filter.add("bitset"); 16 | filter.add("redis"); 17 | System.out.println(filter.contains("bitset")); 18 | System.out.println(filter.contains("redis")); 19 | System.out.println(filter.contains("mysql")); 20 | System.out.println(filter.contains("linux")); 21 | System.out.println(filter.count()); 22 | System.out.println(filter.isEmpty()); 23 | filter.clear(); 24 | System.out.println(filter.isEmpty()); 25 | System.out.println(filter.contains("filter")); 26 | 27 | /** 28 | Test results: 29 | true 30 | false 31 | true 32 | true 33 | false 34 | false 35 | 3 36 | false 37 | true 38 | false 39 | */ 40 | 41 | } 42 | 43 | } 44 | -------------------------------------------------------------------------------- /src/test/java/com/github/wxisme/bloomfilter/bitset/RedisBitSetTest.java: -------------------------------------------------------------------------------- 1 | package com.github.wxisme.bloomfilter.bitset; 2 | 3 | import com.github.wxisme.bloomfilter.common.BloomFilter; 4 | import redis.clients.jedis.HostAndPort; 5 | import redis.clients.jedis.Jedis; 6 | import redis.clients.jedis.JedisCluster; 7 | import redis.clients.jedis.JedisPool; 8 | 9 | import java.util.HashSet; 10 | import java.util.Set; 11 | 12 | public class RedisBitSetTest { 13 | 14 | 15 | public static void main(String[] args) { 16 | 17 | //Don't forget auth password, you better use the configured redis client connection. 18 | //It should be noted that bloomfilter is not responsible for closing and returning redis connection resources. 19 | 20 | //(falsePositiveProbability, expectedNumberOfElements) 21 | BloomFilter filter = new BloomFilter(0.0001, 10000); 22 | Jedis jedis = new Jedis("127.0.0.1", 6379); 23 | jedis.auth("1234"); 24 | filter.bind(new RedisBitSet(jedis, "bloomfilter:key:name")); 25 | 26 | //if you have a redis cluster 27 | //Set nodes = new HashSet<>(); 28 | //nodes.add(new HostAndPort("127.0.0.1", 6379)); 29 | 30 | //filter.bind(new RedisBitSet(new JedisCluster(nodes), "bloomfilter:key:name")); 31 | 32 | //you can also use jedispool 33 | //JedisPool jedisPool = new JedisPool("127.0.0.1", 6379); 34 | //Jedis jedis = jedisPool.getResource(); 35 | //filter.bind(new RedisBitSet(jedis, "bloomfilter:key:name")); 36 | 37 | filter.add("filter"); 38 | System.out.println(filter.contains("filter")); 39 | System.out.println(filter.contains("bloom")); 40 | filter.add("bitset"); 41 | filter.add("redis"); 42 | System.out.println(filter.contains("bitset")); 43 | System.out.println(filter.contains("redis")); 44 | System.out.println(filter.contains("mysql")); 45 | System.out.println(filter.contains("linux")); 46 | System.out.println(filter.count()); 47 | System.out.println(filter.isEmpty()); 48 | filter.clear(); 49 | System.out.println(filter.isEmpty()); 50 | System.out.println(filter.contains("filter")); 51 | 52 | /** 53 | Test results: 54 | true 55 | false 56 | true 57 | true 58 | false 59 | false 60 | 3 61 | false 62 | true 63 | false 64 | */ 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /src/test/java/com/github/wxisme/bloomfilter/bitset/YourBitSet.java: -------------------------------------------------------------------------------- 1 | package com.github.wxisme.bloomfilter.bitset; 2 | 3 | import java.util.Arrays; 4 | 5 | public class YourBitSet implements BaseBitSet { 6 | 7 | private int[] data;//boolean array 8 | 9 | public YourBitSet(int size) { 10 | data = new int[size]; 11 | } 12 | 13 | @Override 14 | public void set(int bitIndex) { 15 | data[bitIndex] = 1; 16 | } 17 | 18 | @Override 19 | public void set(int bitIndex, boolean value) { 20 | if (value) 21 | data[bitIndex] = 1; 22 | else data[bitIndex] = 0; 23 | } 24 | 25 | @Override 26 | public boolean get(int bitIndex) { 27 | return data[bitIndex] == 1; 28 | } 29 | 30 | @Override 31 | public void clear(int bitIndex) { 32 | data[bitIndex] = 0; 33 | } 34 | 35 | @Override 36 | public void clear() { 37 | Arrays.fill(data, 0); 38 | } 39 | 40 | @Override 41 | public long size() { 42 | long size = 0; 43 | for (int d : data) 44 | if (d == 1) 45 | size++; 46 | return size; 47 | } 48 | 49 | @Override 50 | public boolean isEmpty() { 51 | return size() <= 0; 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /src/test/java/com/github/wxisme/bloomfilter/bitset/YourBitSetTest.java: -------------------------------------------------------------------------------- 1 | package com.github.wxisme.bloomfilter.bitset; 2 | 3 | import com.github.wxisme.bloomfilter.common.BloomFilter; 4 | 5 | public class YourBitSetTest { 6 | 7 | public static void main(String[] args) { 8 | //(falsePositiveProbability, expectedNumberOfElements) 9 | BloomFilter filter = new BloomFilter(0.0001, 10000); 10 | filter.bind(new YourBitSet(1000000)); 11 | 12 | filter.add("filter"); 13 | System.out.println(filter.contains("filter")); 14 | System.out.println(filter.contains("bloom")); 15 | filter.add("bitset"); 16 | filter.add("redis"); 17 | System.out.println(filter.contains("bitset")); 18 | System.out.println(filter.contains("redis")); 19 | System.out.println(filter.contains("mysql")); 20 | System.out.println(filter.contains("linux")); 21 | System.out.println(filter.count()); 22 | System.out.println(filter.isEmpty()); 23 | filter.clear(); 24 | System.out.println(filter.isEmpty()); 25 | System.out.println(filter.contains("filter")); 26 | 27 | /** 28 | Test results: 29 | true 30 | false 31 | true 32 | true 33 | false 34 | false 35 | 3 36 | false 37 | true 38 | false 39 | */ 40 | 41 | } 42 | 43 | } 44 | --------------------------------------------------------------------------------