因为工作上要对大量小票数据进行无监督分类,考虑到内存和运算速度的问题,采用巴隆滤波映射对小票的数据进行了处理,工作内容就不详细说了,等项目做完的。
现在谈谈BF(bloom fileter的使用心得
首先,BF是一种基于多哈希映射的转换,随机或者说选取K个质数作为初始种子,这就有了K个哈希映射。一段字符串,每个种子可以得到一个哈希映射,这样这个字符串就对应了多个哈希值,可以降低不同字符串重复覆盖的误识别问题。下面用部分代码举例:
public int hash(String value) {
int result = 0;
int len = value.length();
for (int i = 0; i < len; i++) {
result = seed * result + value.charAt(i);
}
return (cap - 1) & result;
}
这是一个种子(seed)对应的字符串哈希值,然后做个for循环遍历种子数组(seeds),得到字符串对应所有种子的多个哈希值,种子数组举例:private static final int[] seeds = new int[] { 5, 7, 11, 13, 31, 37, 61 };
一般选取质数,个数看识别要求的精度了,具体请参照数学之美中对巴隆滤波的详细讲解,记着里面有个表格列举了部分种子个数的误识别概率,并做了详细推导说明
而之所以计算快,就是因为将大量字符串的比对有效的转换为了bit的比对计算,bit是大数据计算常用的一种数据类型(话说我是学图像的,有的话可能不准确,见谅,这是和一些做数据挖掘的同学闲聊时有些印象,而且我自己工作中如果用java处理图像经常转为bitset类型,一些计算的速度很快),好吧,谁用谁知道。。。
此外,需要注意的是,传统BF不能进行字符串的删除操作,因为不同字符串可能有少量重复元素,如果删除一个字符串的元素,会影响有交叉元素的其他字符串。如果一定要使用字符串的删除功能,可以试试CBF(Count,计数巴隆滤波),顾名思义,就是把bit的0,1记录元素,改为记录这个位置元素出现1的次数,删除时把统计次数减一就行了。
下面贴下整体实现代码,这个就是非原创了,但是具体出处记不清了,因为是一个月前的事了,今天有时间所以对做的项目做个阶段性总结,有知道的请联系我
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.BitSet;
import java.util.List;
public class SimpleBloomFilter {
private static final int DEFAULT_SIZE = 2 << 24;
private static final int[] seeds = new int[] { 5, 7, 11, 13, 31, 37, 61 };
private BitSet bits = new BitSet(DEFAULT_SIZE);
private SimpleHash[] func = new SimpleHash[seeds.length];
public SimpleBloomFilter() {
for (int i = 0; i < seeds.length; i++) {
func[i] = new SimpleHash(DEFAULT_SIZE, seeds[i]);
}
}
public void add(String value) {
for (SimpleHash f : func) {
bits.set(f.hash(value), true);
}
}
public boolean contains(String value) {
if (value == null) {
return false;
}
boolean ret = true;
for (SimpleHash f : func) {
ret = ret && bits.get(f.hash(value));
}
return ret;
}
// 内部类,simpleHash
public static class SimpleHash {
private int cap;
private int seed;
public SimpleHash(int cap, int seed) {
this.cap = cap;
this.seed = seed;
}
public int hash(String value) {
int result = 0;
int len = value.length();
for (int i = 0; i < len; i++) {
result = seed * result + value.charAt(i);
}
return (cap - 1) & result;
}
}
这是几种开源的java代码,我感觉最适用的,没写test,额下面关于项目部分以后补上吧。