哈希表的扩展-布隆过滤器

布隆过滤器的简介

什么是布隆过滤器?

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

为什么会出现布隆过滤器?

在日常生活中,包括在设计计算机软件时,我们经常判断一个元素是否在一个集合中。比如:要检查一个单词是否拼写正确(即是否在已知的字典中);判断一个嫌疑人的名字是否已经在嫌疑名单中;在网络爬虫中,一个网站是否被访问过等等。最直接的方法就是将集合中全部的元素存在计算机中,遇到一个新元素,将它和集合中的元素直接对比。计算机中的集合是用哈希表存储。优点是:快速准确,缺点是:费存储空间。为了提高效率我们可以采用hash表,并且将集合中的元素都映射到bitmap中的一个位上,这样的话就会节省空间和查找的时间。但是由于哈希冲突的原因,我们有可能会产生误判,即不同的元素经过散列函数之后可能产生同一个地址。

布隆过滤器有哪些应用?
1、Google著名的分布式数据库Bigtable使用布隆过滤器来查找不存在的行或列,以减少磁盘查找IO的次数。
2、Squid网页代理缓存服务在cache digests 。
3、Venti文档存储系统也采用布隆过滤器来检测先前存储的数据。
4、SPIN模型检测器使用布隆过滤器在大规模验证问题时跟踪可达状态空间。
5、Google Chrome浏览器使用布隆过滤器加速安全浏览服务。
6、在很多Key-Value系统也使用了布隆过滤器加快查询过程。如:Hbase、Accumulo、Leveldb。


简单的实现布隆过滤器

BitSet.h
#pragma once

#include <vector>

class BitSet
{
public:
    BitSet(size_t range)//构造函数
    {
        _a.resize((range >> 5) + 1, 0);
    }

    void Set(size_t num)
    {
        size_t index = num >> 5;//在哪个数中
        size_t pos = num % 32;//在哪个比特位中

        _a[index] |= (1 << pos);//将num对应的位置1
    }

    void ReSet(size_t num)
    {
        size_t index = num >> 5;
        size_t pos = num % 32;

        _a[index] &= ~(1 << pos);//将num对应的位置0
    }

    bool Test(size_t num)
    {
        size_t index = num >> 5;
        size_t pos = num % 32;

        return _a[index] & (1 << pos);//如果存在,对应的位是1,&1为1,否则相反
    }

protected:
    vector<int> _a;
};

BloomFilter.h
#pragma once

template <typename K>
struct _Func1
{
    size_t BKDRHash(const char *str)
    {
        register size_t hash = 0;
        while (size_t ch = (size_t)*str++)
        {
            hash = hash * 131 + ch;   // 也可以乘以31、131、1313、13131、131313..           
        }
        return hash;
    }
    size_t operator()(const string& key)
    {
        return BKDRHash(key.c_str());
    }
};

template <typename K>
struct _Func2
{
    size_t SDBMHash(const char *str)
    {
        register size_t hash = 0;
        while (size_t ch = (size_t)*str++)
        {
            hash = 65599 * hash + ch;
            //hash = (size_t)ch + (hash << 6) + (hash << 16) - hash;  
        }
        return hash;
    }
    size_t operator()(const string& key)
    {
        return SDBMHash(key.c_str());
    }
};

template <typename K>
struct _Func3
{
    size_t RSHash(const char *str)
    {
        register size_t hash = 0;
        size_t magic = 63689;
        while (size_t ch = (size_t)*str++)
        {
            hash = hash * magic + ch;
            magic *= 378551;
        }
        return hash;
    }

    size_t operator()(const string& key)
    {
        return RSHash(key.c_str());
    }
};

template <typename K>
struct _Func4
{
    size_t APHash(const char *str)
    {
        register size_t hash = 0;
        size_t ch;
        for (long i = 0; ch = (size_t)*str++; i++)
        {
            if ((i & 1) == 0)
            {
                hash ^= ((hash << 7) ^ ch ^ (hash >> 3));
            }
            else
            {
                hash ^= (~((hash << 11) ^ ch ^ (hash >> 5)));
            }
        }
        return hash;
    }
    size_t operator()(const string& key)
    {
        return APHash(key.c_str());
    }
};

template <typename K>
struct _Func5
{
    size_t JSHash(const char *str)
    {
        if (!*str)        // 这是由本人添加,以保证空字符串返回哈希值0  
            return 0;
        register size_t hash = 1315423911;
        while (size_t ch = (size_t)*str++)
        {
            hash ^= ((hash << 5) + ch + (hash >> 2));
        }
        return hash;
    }
    size_t operator()(const string& key)
    {
        return JSHash(key.c_str());
    }
};

template <typename K = string
    , typename Func1 = _Func1<K>
    , typename Func2 = _Func2<K>
    , typename Func3 = _Func3<K>
    , typename Func4 = _Func4<K>
    , typename Func5 = _Func5<K >>
class BloomFilter
{
public:
    BloomFilter(const size_t range)
        :_s1(range)
        , _size(range)
    {}

    void Set(const K& key)
    {
        size_t index1 = Func1()(key.c_str()) % _size;
        size_t index2 = Func2()(key.c_str()) % _size;
        size_t index3 = Func3()(key.c_str()) % _size;
        size_t index4 = Func4()(key.c_str()) % _size;
        size_t index5 = Func5()(key.c_str()) % _size;

        _s1.Set(index1);
        _s1.Set(index2);
        _s1.Set(index3);
        _s1.Set(index4);
        _s1.Set(index5);
    }

    bool Test(const K& key)
    {
        size_t index1 = Func1()(key.c_str()) % _size;
        _s1.Test(index1);
        if (_s1.Test(index1) == 0)
            return false;

        size_t index2 = Func2()(key.c_str()) % _size;
        _s1.Test(index2);
        if (_s1.Test(index2) == 0)
            return false;

        size_t index3 = Func3()(key.c_str()) % _size;
        _s1.Test(index3);
        if (_s1.Test(index3) == 0)
            return false;

        size_t index4 = Func4()(key.c_str()) % _size;
        _s1.Test(index4);
        if (_s1.Test(index4) == 0)
            return false;

        size_t index5 = Func1()(key.c_str()) % _size;
        _s1.Test(index5);
        if (_s1.Test(index5) == 0)
            return false;
        return true;
    }
protected:
    BitSet _s1;
    size_t _size;
};

void TestBloomFilter()
{
    BloomFilter<> bf1(1000);
    bf1.Set("sort");
    bf1.Set("man");
    bf1.Set("left");
    bf1.Set("123");
    bf1.Set("真的");
    bf1.Set("https://hao.360.cn/?a1006");
    bf1.Set("https://hao.360.cn/?a10061");
    bf1.Set("https://hao.360.cn/?a10062");
    bf1.Set("https://hao.360.cn/?a10063");
    bf1.Set("https://hao.360.cn/?a10064");

    cout << "Is True?:" << bf1.Test("sort") << endl;
    cout << "Is True?:" << bf1.Test("123") << endl;
    cout << "Is True?:" << bf1.Test("left1") << endl;
    cout << "Is True?:" << bf1.Test("真的") << endl;
    cout << "Is True?:" << bf1.Test("假的") << endl;
    cout << "Is True?:" << bf1.Test("https://hao.360.cn/?a1006") << endl;
    cout << "Is True?:" << bf1.Test("https://hao.360.cn/?a10064") << endl;
    cout << "Is True?:" << bf1.Test("https://hao.360.cn/?a10067") << endl;
}

Test.cpp
#include <iostream>
#include <string>
#include <cassert>
#include <cstdlib>

using namespace std;

#include "BitSet.h"
#include "BloomFilter.h"

int main()
{
    TestBloomFilter();
    return 0;
}
<think>好的,我需要回答用户关于布隆过滤器在操作系统内核中的应用与实现的问题。首先,我要回忆布隆过滤器的基本概念,它是一个概率型数据结构,用于判断元素是否在集合中,可能会有误判但不会漏判。接下来,我需要查找操作系统内核中哪些地方可能用到布隆过滤器。根据用户提供的引用,特别是引用[5]提到I/O调度层管理块设备的请求队列,合并请求,可能用布隆过滤器来快速判断请求是否已存在,避免重复处理。 另外,网络子系统中的包过滤或连接跟踪也可能应用布隆过滤器,例如快速过滤恶意IP或端口。内存管理方面,如页面缓存或slab分配器中,判断某些页面是否被缓存,减少扫描时间。文件系统中,快速判断文件路径或inode是否存在,加速元数据查询。 实现方面,内核中的布隆过滤器需要考虑内存分配和位操作的高效性。可能需要使用内核提供的位图API,如bitmap_set和bitmap_test。同时,动态扩展布隆过滤器可能需要多层结构,但内核资源有限,需权衡内存和性能。误判率控制也很重要,特别是在关键路径上,高误判可能影响系统稳定性。 需要注意的是,虽然布隆过滤器在内核中有潜在应用,但实际实现可能因内核版本和子系统而异。用户提供的引用中没有直接提到内核中的布隆过滤器,但可以推测其应用场景。例如引用[3]提到过滤器过短导致失效的问题,内核实现时需合理设计哈希函数数量和位数组大小。引用[5]的I/O调度层合并请求可能与布隆过滤器结合,优化请求处理。 最后,要确保回答结构清晰,分点说明应用场景和实现要点,并附上相关问题。引用相关文献时正确标注,如引用[5]关于I/O调度层的内容。可能还需要补充内核中实际使用布隆过滤器的例子,如某些文件系统或网络模块的具体实现,但若缺乏具体信息,需说明可能的应用方向而非具体实例。</think>### 布隆过滤器在操作系统内核中的应用与实现 #### 1. **应用场景** 布隆过滤器在内核中主要用于**快速判断数据是否存在**,以减少不必要的计算或I/O开销,具体应用包括: - **I/O请求合并与缓存管理** 在块设备I/O调度层(如Linux内核的`elevator`调度器),布隆过滤器可快速判断某个请求是否已被缓存或合并。例如,通过记录已处理的磁盘扇区范围,避免重复处理相同请求,从而优化I/O性能[^5]。 - **网络数据包过滤** 在网络子系统中(如Netfilter框架),布隆过滤器可用于快速过滤恶意IP地址或端口。例如,内核模块可能用其判断某个IP是否在黑名单中,减少遍历哈希表或链表的开销。 - **内存管理优化** 在内存页管理(如页面缓存或slab分配器)中,布隆过滤器可快速判断某个页是否已被缓存,减少无效的页表遍历操作。 - **文件系统元数据查询** 文件系统(如ext4或Btrfs)可能用布隆过滤器加速元数据查询,例如判断某个文件路径的inode是否已被加载到内存中。 --- #### 2. **实现要点** 在内核中实现布隆过滤器需考虑以下关键问题: - **内存分配与位操作** 内核中通常使用`bitmap`结构表示布隆过滤器的位数组,通过`kzalloc`等函数动态分配内存。位操作通过内核提供的`set_bit()`和`test_bit()`等原子操作实现。 - **哈希函数设计** 内核需选择高效且分布均匀的哈希函数。例如,可能组合使用`jhash`(Jenkins哈希)和`crc32`等轻量级哈希函数。 - **动态扩展与误判率控制** 若需动态扩展容量,可参考**可扩展布隆过滤器**(Scalable Bloom Filter)的设计,但内核中更倾向静态预分配以降低复杂度。误判率需通过调整位数组大小和哈希函数数量控制[^1]。 --- #### 3. **示例代码(伪代码)** 以下是一个简化的内核模块中布隆过滤器的实现框架: ```c #include <linux/bitmap.h> #define BLOOM_SIZE 8192 // 位数组大小 static unsigned long bloom_filter[BITS_TO_LONGS(BLOOM_SIZE)]; // 添加元素 void bloom_add(const void *data, size_t len) { u32 hash1 = jhash(data, len, 0) % BLOOM_SIZE; u32 hash2 = crc32_le(0, data, len) % BLOOM_SIZE; set_bit(hash1, bloom_filter); set_bit(hash2, bloom_filter); } // 判断元素是否存在 bool bloom_test(const void *data, size_t len) { u32 hash1 = jhash(data, len, 0) % BLOOM_SIZE; u32 hash2 = crc32_le(0, data, len) % BLOOM_SIZE; return test_bit(hash1, bloom_filter) && test_bit(hash2, bloom_filter); } ``` --- #### 4. **挑战与限制** - **内存限制**:内核内存有限,需权衡位数组大小与误判率[^3]。 - **并发安全**:需使用原子操作或锁机制保证多线程安全。 - **误判对系统的影响**:若用于关键路径(如安全检测),需结合其他机制(如二次确认)降低风险。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值