Gao Conghui

好好学习,天天向上

爬虫,视频处理


布隆过滤器扩容及删除过期数据

我们知道,布隆过滤器是不可变的,但如果布隆过滤器容量确实不够了,该怎么办呢?或者如果要每个月都删除几个月前的去重数据,该如何处理呢?这边要记录一种布隆过滤器的巧用,多个布隆过滤器组成的循环布隆过滤器。

布隆过滤器

布隆过滤器的细节这边不做赘述,他在创建的时候就确定了容量以及错误率(false postive),为了后续的方便,这边假设我们有了一个可靠的布隆过滤器。

class BloomFilter(object):
    def __init__(self, capacity, error_rate):
      	pass
    def add(self,key):
    	pass
    def exists(self,key):
      	pass
    def __len__(self):
      	pass

很简单的一个结构,接下去我们会用基础的布隆过滤器去实现最开始说的两个需求。

布隆过滤器扩容

因为布隆过滤器的不可逆,我们没法重新建一个更大的布隆过滤器然后去把数据重新导入。这边采取的扩容的方法是,保留原有的布隆过滤器,建立一个更大的,新增数据都放在新的布隆过滤器中,去重的时候检查所有的布隆过滤器。

class BloomFilterAdapter(object):
    def __init__(self, old_filters, new_filter):
        self.old_filters = old_filters
        self.new_filter = new_filter

    def add(self, key):
        self.new_filter.add(key)

    def exists(self, key):
        return any([f.exists(key) for f in self.old_filters]) or self.new_filter.exists(key)

    def __len__(self):
        return sum([len(f) for f in self.old_filters]) + len(self.new_filter)

非常巧妙的方法,用一个新的布隆过滤器和多个老的布隆过滤器共同组成一个新的过滤器,提供相同的接口。

附带时效的布隆过滤器

为了实现这么一个需求:使用布隆过滤器对url去重,但是每五个月要重新爬取一次。这边介绍一种循环的布隆过滤器,类似于之前的思路,由多个布隆过滤器组成,每个月都清空最早的那个过滤器。demo如下。

class CircleBloomFilter(object):
    def __init__(self, filter_num):
        """
        :param filter_num: 预期包含的filter数量
        """
        self.filter_num = filter_num
        self.filters = [new_bloomfilter()]

    def do_circle(self):
        """
        执行循环逻辑
        :return: 
        """
        if len(self.filters) >= self.filter_num:
            self.filters.pop(0)
        self.filters.append(new_bloomfilter())

    def add(self, key):
        self.filters[-1].add(key)

    def exists(self,key):
        return any([f.exists(key) for f in self.filters])
    
    def __len__(self):
        return sum([len(f) for f in self.filters])

一样非常简单的逻辑,只要定期执行do_circle即可。

另外,我们可以看到,上边的实现add方法只对一个过滤器执行,而exists方法对所有过滤器都要执行,比较适用于插入多,但是判断是否重复少的场景。我们还可以换一种方式,应对查询是否重复大于添加操作的场景。

    def add(self,key):
        [f.add(key) for f in self.filters]
        
    def exists(self,key):
        return self.filters[0].exists(key)

每次的插入操作,我们对所有的过滤器都执行,而查询是否重复,只需要查询最早的过滤器是否存在即可(包含了全部的数据)

最近的文章

scons 简单入门

简单入门hello worldscons由Sconstruct 作为入口,控制如何进行编译操作。Sconstruct 本身是一个python文件,故需要遵循python的语法,以及能使用一些python的方法。(如我们可以用print 来debug)这有一段很简单的hello.cpp#include <iostream>int main() { std::cout << "hello world" << std::endl;}以及一个很简单的Sco...…

build scons继续阅读
更早的文章

mac vpn翻墙,部分网站走vpn

需求是这样,现在有一个vpn,我可以通过这个vpn翻墙,但同时我需要访问内网,换言之,就是需要白名单或者黑名单翻墙的机制。mac上使用vpn很方便,偏好设置中就可以直接弄,但是没找到合适的黑白名单机制,没办法,只能另辟蹊径,通过iptable来指定不同的ip走不同的网卡。 通过ifconfig找到vpn使用的虚拟网卡名以及非vpn的时候使用的网卡 lo0: flags=8049<UP,LOOPBACK,RUNNING,MULTICAST> mtu 16384 o...…

网络继续阅读