文档章节

一个简单的布隆过滤器

a
 alex_wei
发布于 2013/07/03 02:39
字数 880
阅读 252
收藏 11
点赞 0
评论 0

布隆过滤器(Bloom Filter)是1970年由布隆提出的。它实际上是一个很长的二进制向量和一系列随机映射函数。布隆过滤器可以用于检索一个元素是否在一个集合中。它的优点是空间效率和查询时间都远远超过一般的算法,缺点是有一定的误识别率和删除困难。

——摘自维基百科

因为查找别的资料,偶尔发现这一利器。兴趣所致,写了一个简单的C实现。当然很多问题没有考虑在内,仅就核心概念给出了一个缩略版实现,做为一个提醒,加深一下印象。

simple_bf.h:

#ifndef _SIMPLE_BF_H_
#define _SIMPLE_BF_H_

#include <stdint.h>
#include <stdbool.h>

#define VEC_LEN (1024 * 1024 * 64 + 1)

#ifdef __cplusplus
extern "C" {
#endif

typedef struct _bf_vec {
        uint64_t part[VEC_LEN];
} bf_vec_t;

extern bool bf_add(bf_vec_t *vec, const char *str);

extern bool bf_is_contains(bf_vec_t *vec, const char *str);

#ifndef likely
#define likely(x) __builtin_expect((x),1)
#endif

#ifndef unlikely
#define unlikely(x) __builtin_expect((x),0)
#endif

#ifdef __cplusplus
}
#endif

#endif
simple_bf.c:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "simple_bf.h"

/* return false means the arg bit is over the bit length of the arg vec,
 * otherwise return true means successfully set the right bit.
 * for simple, only consider about these two conditions */
static inline __attribute__((always_inline)) bool bf_set_bit(bf_vec_t *vec, uint64_t bit)
{
	uint64_t part_cnt = bit / 64;
	if (unlikely(part_cnt > VEC_LEN))
		return false;
	uint8_t mod = bit % 64;
	vec->part[part_cnt] |= (1ULL << mod);
	return true;	
}

static inline __attribute__((always_inline)) bool bf_test_bit(bf_vec_t *vec, uint64_t bit)
{
	uint64_t part_cnt = bit / 64;
	if (unlikely(part_cnt > VEC_LEN))
		return false;
	uint8_t mod = bit % 64;
	return ((vec->part[part_cnt] & (1ULL << mod)) != 0);	
}

/* the seed vector and the BKDR hash function */
static uint32_t seeds[8] = {31, 131, 1313, 13131, 131313, 1313131, 13131313, 131313131};
static uint32_t bkdr_hash_modified(const char *str, uint32_t seed)
{
	register uint32_t hash = 0;
	uint32_t ch;
	while ((ch = (uint32_t)*str++)) {
		hash = hash * seed + ch;
	}
	return hash;
}

bool bf_add(bf_vec_t *vec, const char *str)
{
	int i;
	for (i = 0; i < 8; ++i) {
		uint32_t val = bkdr_hash_modified(str, seeds[i]);
		if (!bf_set_bit(vec, val))
			return false;
	}
	return true;
}

bool bf_is_contains(bf_vec_t *vec, const char *str)
{
	int i;
	for (i = 0; i < 8; ++i) {
		uint32_t val = bkdr_hash_modified(str, seeds[i]);
		if (!bf_test_bit(vec, val))
			return false;
	}
	return true;
}

#ifndef NDEBUG 
int main1(int argc, char *argv[])
{
	if (argc < 3) {
		fprintf(stderr, "usage: bf as0 [as1 as2 ...] ts\n"
				"as means string to add to the bloom filter\n"
				"ts means the string to test if it is in the filter vector\n"
				);
		return 1;
	}

	bf_vec_t *vec = calloc(1, sizeof(bf_vec_t));
	if (vec == NULL)
		return 1;
		
	int i;
	for (i = 1; i < argc - 1; ++i) {
		if (bf_add(vec, argv[i]))
			printf("add to bloom filter successed, string %s\n", argv[i]);
		else
			printf("add to bloom filter FAILED, string %s\n", argv[i]);
	}
	printf("------------------------------------------------------------------\n");
	if (bf_is_contains(vec, argv[argc - 1]))
		printf("test string %s is in bloom filter\n", argv[argc - 1]);
	else
		printf("test string %s is NOT in bloom filter\n", argv[argc - 1]);

	free(vec);
	return 0;
}

int main2(int argc, char *argv[])
{
	if (argc != 3) {
		fprintf(stderr, "usage: bf filename ts\n"
			"file of filename contains the strings to be added\n"
			"ts means the string to test if it is in the filter vector\n"
			);
		return 1;
	}

	bf_vec_t *vec = calloc(1, sizeof(bf_vec_t));
	if (vec == NULL)
		return 1;
	
	char buf[128] = {0};	
	FILE *fp = fopen(argv[1], "rt");
	if (fp == NULL) {
		free(vec);
		return 1;
	}
	while (fgets(buf, sizeof(buf), fp) != NULL) {
		buf[strlen(buf) - 1] = '\0';
		if (bf_add(vec, buf))
			printf("add to bloom filter successed, string %s\n", buf);
		else
			printf("add to bloom filter FAILED, string %s\n", buf);
	}

	printf("------------------------------------------------------------------\n");
	if (bf_is_contains(vec, argv[2]))
		printf("test string %s is in bloom filter\n", argv[2]);
	else
		printf("test string %s is NOT in bloom filter\n", argv[2]);
	
	free(vec);
	return 0;
}

int main(int argc, char *argv[])
{
	return main2(argc, argv);
}
#endif
在Linux 2.6.39.4 SMP x86_64 gcc version 4.4.3下做了简单测试,效率还是比较可观的。没有做量化的效率测试,也没有对误判率做量化测试。

我在考虑是不是要加一个谓词回调接口,类似于:

typedef int (*bf_contains_cb)(void *data);
int bf_oper_if_contains(bf_vec_t *vec, const char *str, bf_contains_cb callback, void *data);
这样可用性应该会好一些。暂且放下,等到真正要用时,再做详细的量化测试和代码完善吧。

© 著作权归作者所有

共有 人打赏支持
a
粉丝 2
博文 6
码字总数 2777
作品 0
海淀
程序员
布隆过滤器(Bloom Filter)

基本概念 如果想判断一个元素是不是在一个集合里,一般想到的是将所有元素保存起来,然后通过比较确定。链表、树、散列表(又叫哈希表,Hash table)等等数据结构都是这种思路。但是随着集合...

行者PHPer ⋅ 2014/04/12 ⋅ 0

如何实现大数据集查询?Bloom Filter或许是你想要的

1、什么情况下需要布隆过滤器? 先来看几个比较常见的例子 字处理软件中,需要检查一个英语单词是否拼写正确 在 FBI,一个嫌疑人的名字是否已经在嫌疑名单上 在网络爬虫里,一个网址是否被访...

流川枫AI ⋅ 2017/06/18 ⋅ 0

网络爬虫之url等高效率去重原理

布隆过滤器用于字符串去重复,比如网络爬虫抓取时URL去重、邮件提供商反垃圾黑名单Email地址去重。等等。用哈希表也可以用于元素去重,但是占用空间比较大,而且空间使用率只有50%。   布隆...

小湘西 ⋅ 2015/11/12 ⋅ 0

海量数据判重——布隆过滤器(Bloom filter)与Bitmap对比

前言 之前写过一篇Bitmap在海量整数排序中应用的博客,在看过布隆过滤器之后,感觉两个有些相似,但是又有区别,在查阅了很多资料之后,这里决定稍作总结。 关于布隆过滤器(Bloom filter)的...

tick_tock97 ⋅ 2017/12/01 ⋅ 0

BloomFilter布隆过滤器使用

从上一篇可以得知,BloomFilter的关键在于hash算法的设定和bit数组的大小确定,通过权衡得到一个错误概率可以接受的结果。 算法比较复杂,也不是我们研究的范畴,我们直接使用已有的实现。 ...

辣妈程序媛 ⋅ 03/11 ⋅ 0

布隆过滤器实现JAVA

概述 布隆过滤器的作用是加快判定一个元素是否在集合中出现的方法。因为其主要是过滤掉了大部分元素间的精确匹配,故称为过滤器。 其应用场景为需要频繁在一个海量的集合中查找某个元素是否存...

dugangabc ⋅ 2016/04/14 ⋅ 0

HBase列族高级配置

HBase有几个高级特性,在你设计表时可以使用。这些特性不一定联系到模式或行键设计,但是它们定义了某些方面的表行为。本节我们讨论这些配置参数,以及你可以如何使用它们。 1 可配置的数据块...

八戒_o ⋅ 2016/01/03 ⋅ 0

[转载]HBase列族高级配置

HBase有几个高级特性,在你设计表时可以使用。这些特性不一定联系到模式或行键设计,但是它们定义了某些方面的表行为。本节我们讨论这些配置参数,以及你可以如何使用它们。 1 可配置的数据块...

2k10 ⋅ 2016/02/03 ⋅ 1

算法分析:使用布隆过滤器(Bloom Filter)进行大数据量排序

题目大意:移动公司需要对已经发放的所有139段的号码进行统计排序,已经发放的139号码段的文件都存放在一个文本文件中(原题是放在两个文件中),一个号码一行,现在需要将文件里的所有号码进...

苗哥 ⋅ 2014/03/20 ⋅ 3

Bloom filter在分布式环境中的应用

Bloom filter在分布式环境中的应用 未命名2017-05-0427 阅读 filter技术分布式 概述 布隆过滤器是一个应用非常广泛的概率型数据结构,一般用于判断一个元素是否存在一个集合中,比如在字处理...

未命名 ⋅ 2017/05/04 ⋅ 0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

从方法论到零售客户实践 解码阿里巴巴数据中台——2018上海云栖大会

摘要: 一、数据中台之道 6月8日,上海云栖大会进入了第二天的议程,数据中台专场论坛座无虚席,数据中台总架构师邓中华女士向在场的观众介绍了数据中台的衍生发展之道。 基于OneID、OneData...

阿里云云栖社区 ⋅ 23分钟前 ⋅ 0

Ubuntu部署django问题汇总

使用Anaconda3的Python3.6的pip安装UWSGI报错 原因是gcc版本不兼容,安装4.7并修改gccsudo apt-get install gcc-4.7sudo mv /usr/bin/gcc /usr/bin/gcc.baksudo ln -s /usr/bin/gcc-4.......

wuyaSama ⋅ 26分钟前 ⋅ 0

从方法论到零售客户实践 解码阿里巴巴数据中台——2018上海云栖大会

摘要: 一、数据中台之道 6月8日,上海云栖大会进入了第二天的议程,数据中台专场论坛座无虚席,数据中台总架构师邓中华女士向在场的观众介绍了数据中台的衍生发展之道。 基于OneID、OneData...

猫耳m ⋅ 26分钟前 ⋅ 0

Docker减肥小记

如果经常使用 docker,你会发现 docker 占用的资源膨胀很快,其中最明显也最容易被察 如何快速的清理 docker 占用的系统资源,具体点说就是删除那些无用的镜像、容器、网络和数据卷… 1、查看...

寰宇01 ⋅ 37分钟前 ⋅ 0

微信小程序中如何使用WebSocket实现长连接(含完整源码)

本文由腾讯云技术团队原创,感谢作者的分享。 1、前言 微信小程序提供了一套在微信上运行小程序的解决方案,有比较完整的框架、组件以及 API,在这个平台上面的想象空间很大。腾讯云研究了一...

JackJiang- ⋅ 45分钟前 ⋅ 0

定制库到Maven本地资源库

1.如果只有定制库的JAR文件 下载链接如下:pdf.jar 2.使用命令转换成Maven本地资源 mvn install:install-file -Dfile=/Users/manager/Downloads/clj-pdf-2.2.33.jar -DgroupId=clj-pdf -Dar......

年少爱追梦 ⋅ 49分钟前 ⋅ 0

高仿springmvc之xuchen-mvc

package org.mvc.framework.servlet; import java.io.BufferedReader; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.File; import java.io.......

徐志 ⋅ 51分钟前 ⋅ 0

关于自定义URLStreamHandler的一次踩坑

关于自定义URLStreamHandler的一次踩坑 20180625 lambo init 说明 一般自定义实现url的协议解析.方案为实现URLStreamHandler.实现其 openConnection 就可以了, 如果我们执行 new URL("xx://...

林小宝 ⋅ 52分钟前 ⋅ 0

【SM2证书】利用BC的X509v3CertificateBuilder组装X509国密证书

演示证书文件 链接: https://pan.baidu.com/s/1ijHNnMQJj7jzW-jXEVd6Gg 密码: vfva 所需jar包 <!-- https://mvnrepository.com/artifact/org.bouncycastle/bcpkix-jdk15on --> <dependenc......

小帅帅丶 ⋅ 53分钟前 ⋅ 0

用Calendar 实现 计算 一段时间的毫秒值

Calendar c=Calendar.getInstance();c.add(Calendar.MONTH, -1);int lastMonthMaxDay=c.getActualMaximum(Calendar.DAY_OF_MONTH);c.set(c.get(Calendar.YEAR), c.get(Calendar.MONTH)......

岸芷汀兰 ⋅ 57分钟前 ⋅ 0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

返回顶部
顶部