【问题标题】:Opposite of Bloom filter?与布隆过滤器相反?
【发布时间】:2010-10-12 18:03:41
【问题描述】:

我正在尝试优化一个基本上运行数百万次测试的软件。这些测试的生成方式可以有一些重复。当然,如果我能有效地避免它,我不想花时间运行我已经运行过的测试。

所以,我正在考虑使用 Bloom 过滤器来存储已经运行的测试。然而,布隆过滤器对我来说是不安全的。它给出了误报。也就是说,它可能会报告我已经运行了一个我没有运行过的测试。虽然这在我正在处理的场景中是可以接受的,但我想知道是否有与 Bloom 过滤器等效的方法,但在相反的方面犯了错误,即只给出假阴性。

我浏览了文献,没有任何运气。

【问题讨论】:

标签: data-structures bloom-filter


【解决方案1】:

不,如果您考虑一下,它不会很有用。在您的情况下,您无法确定您的测试运行是否会停止,因为如果总是存在“假阴性”,那么总会有需要运行的测试......

我会说你只需要使用一个哈希。

【讨论】:

  • 感谢您的回复。我认为它仍然很有用,因为我总是可以在固定时间后停下来。事实上,我可以永远继续生成测试。但是这样的数据结构将帮助我确保大多数测试实际上都是新的,而不会很快耗尽内存。
【解决方案2】:

是否可以存储您运行的测试?这应该与过滤器的行为相反。

【讨论】:

【解决方案3】:

LRUCache 怎么样?

【讨论】:

    【解决方案4】:

    对不起,我帮不上什么忙——我认为这不可能。如果无法对测试执行进行排序,则可以使用打包格式(每字节 8 个测试!)或用于将结果存储在内存中的良好稀疏数组库。

    【讨论】:

      【解决方案5】:

      我认为您遗漏了部分解决方案;为了完全避免误报,您仍然必须跟踪哪些已经运行,并且基本上使用布隆过滤器作为确定测试肯定没有运行的快捷方式。

      也就是说,由于您事先知道测试的数量,您可以使用一些众所周知的公式来调整过滤器的大小,以提供可接受的错误率;对于返回误报的概率为 1%,您需要 ~9.5 位/条目,因此对于一百万个条目,1.2 兆字节就足够了。如果您将可接受的错误率降低到 0.1%,这只会增加到 1.8 MB。

      Wikipedia 文章 Bloom Filters 提供了出色的分析,并对所涉及的数学进行了有趣的概述。

      【讨论】:

        【解决方案6】:

        是的,有损哈希表或 LRUCache 是一种具有快速 O(1) 查找的数据结构,只会给出假阴性——如果您问“我是否运行测试 X”,它会告诉您“是,你肯定有”,或者“我不记得了”。

        原谅极其粗糙的伪代码:

        setup_test_table():
            create test_table( some large number of entries )
            clear each entry( test_table, NEVER )
            return test_table
        
        has_test_been_run_before( new_test_details, test_table ):
            index = hash( test_details , test_table.length )
            old_details = test_table[index].detail
            // unconditionally overwrite old details with new details, LRU fashion.
            // perhaps some other collision resolution technique might be better.
            test_table[index].details = new_test_details
            if ( old_details === test_details ) return YES
            else if ( old_details === NEVER ) return NEVER
            else return PERHAPS    
        
        main()
            test_table = setup_test_table();
            loop
                test_details = generate_random_test()
                status = has_test_been_run_before( test_details, test_table )
                case status of
                   YES: do nothing;
                   NEVER: run test (test_details);
                   PERHAPS: if( rand()&1 ) run test (test_details);
            next loop
        end.
        

        【讨论】:

        • 我要补充一点,任何将内存模型与驱逐策略(如 MRU、LFU 或 ARC)相结合的答案都是此问题的有效答案。
        • 虽然任何具有离散成员的有损集合都可以说是被认为与具有概率成员的集合“相反”的数据结构家族,但 LRU 启发式是一个完全独立的关注点,与这个问题。诚然,如果我们要概括的话,我自己的答案也是如此(它假设关联性为 1)。只要说定义了一个变换f(set, item) -> set' 就足够了,给定一个set 和一个item,将产生一个新的set',它可能包括item 作为成员,受基数约束。 f 的选择无关紧要
        【解决方案7】:

        完成此任务的确切数据结构是Direct-mapped cache,通常用于 CPU。

        function set_member(set, item)
            set[hash(item) % set.length] = item
        
        function is_member(set, item)
            return set[hash(item) % set.length] == item
        

        【讨论】:

        • 同样以百万计,您可以使用简单的位数组。 :)
        【解决方案8】:

        您期望的数据结构不存在。因为这样的数据结构必须是多对一的映射,或者说,一个有限的状态集。必须至少有两个不同的输入映射到相同的内部状态。因此,您无法判断它们是否都(或更多)都在集合中,只知道至少存在一个这样的输入。

        EDIT 仅当您正在寻找一种内存效率高的数据结构时,此语句才是正确的。如果内存是无限的,您总是可以通过存储每个成员项来获得一个数据结构来提供 100% 准确的结果。

        【讨论】:

        • @MartinKällman 如果不需要内存效率,那么您是正确的,因为上面提出的所有解决方案都需要存储原始项目(在您的情况下为 set_member)。达到内存限制后,它会给出假阴性和假阳性结果。即使由于输入过多导致误报率相当高,Bloom Filter 也不会给出误报结果。
        • 是的,这是任何关联数组的要求
        【解决方案9】:
        1. 如上所述,使用位设置。如果你知道没有。在您将要预先运行的测试中,您将始终从数据结构中获得正确的结果(存在、不存在)。
        2. 您知道要散列的密钥是什么吗?如果是这样,您应该运行一个实验来查看 BloomFilter 中键的分布,以便您可以对其进行微调以重现误报,或者您有什么。
        3. 您可能还想查看 HyperLogLog。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2019-07-04
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2011-09-22
          • 2023-04-09
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多