交叉点设置为空时快速检查(误报是否正常)

时间:2017-11-20 13:17:20

标签: algorithm data-structures probability bloom-filter

如果两个集合的交集(一个对于所有检查都相同,另一个更改)是空的或者不是,我需要做很多检查。

如果检查说(在少量检查中)它不是空的,那就没关系,但它是(可能有更精确的第二个过滤步骤),所以误报是好。这是不允许的,我过滤掉了一些非空的交叉点,所以假阴性是不行的。

所以,只有一个场景:

marker(交集中的D),永远不允许为假

linestyle='None'(没有交集)也可以在少量检查中返回

对于单个元素,我会使用布隆过滤器,但我找不到类似于一组元素的东西,并且逐个元素布隆过滤器检查是一个可能的选项,但我正在寻找更好的东西。

3 个答案:

答案 0 :(得分:2)

非常感谢您的回答,帮助我提出了一个很好的解决方案并解决了问题。

这个想法大部分都是原始的,但足够了。

我创建了两个位集,一个用于更改集,另一个用于固定集。一组中的每个元素被散列为一位(例如,对于1到64中的长位),然后组合成一组(大多数是Bloom-Bitset,其中k = 1)。

要检查是否存在非空交集,我只需要将两个位集与位和操作组合,并检查结果是否为0。

假阳性率(我认为,没有做数学)会更糟,但对我的情况来说已经足够好了。

示例:

[A,B,C] => 0000100010100000

[B,D,F] => 0100000010000100

----------------------&

0000000010000000!= 0 =>真

答案 1 :(得分:0)

一个优化是保持列表(快速查找的数组)与每个集的最小/最大值。然后首先检查该列表是否重叠。如果不是 - >返回false - 不需要进一步检查。

S1: a b c
S2:       d e f

S1 and S2 -> false (no overlap)

如果对这些集进行排序并且它们重叠,则只需检查重叠区域。

S1: a b c d e
S2:       d e f g h

Only check the 'd e' region

如果需要检查两组以上的交集,首先尝试查找两个不重叠的集合。如果找到 - >返回false。如果没有,只检查所有这些集合的重叠区域(对于更多集合,它应该变小)。

S1: a b c d e
S2:       d e f g h
S3:             g h i

S1 and S2 and S3 -> false (S1 and S3 do not overlap)

如果大多数集合范围很广,您可以使用其他选项:

假设元素的最大数量是6400(对于此示例),并且每个元素都是,或者可以转换为1-6400的整数。

对于每个集合,可以创建一个小位图(64位无符号整数),其中一位代表100个项目。

例如:

S1: 1,23,80,312,340
S2: 160,184,450
S3: 230,250,340

S1 bitmap: 100100..
S2 bitmap: 010010..
S3 bitmap: 001100..

S1 and S2 -> false
S1 and S3 -> true, only check range 301-400
S1 and S2 and S3 -> false

您当然可以使用小于100的数字(最好是2的幂,因此您可以快速设置相应的位)并使用多个uint64

这甚至可以在多个级别中完成(取决于您愿意使用的内存/存储空间量)。例如,首先快速检查一个64位整数(占用一个CPU周期,可以很容易地用SQL完成)。只有匹配的那些才能检查包含4,8或16 uint64的第二级,每个位代表一个较小的值范围(使用SSE / AVX寄存器也可能非常快)。如果它们仍然匹配,则进行更深入的检查,但仅针对与结果中的设置位相对应的范围。

答案 2 :(得分:0)

你提到你是在sql做的。所以我们这样说:

  • PatternSet (ElemId int16 primary key):带有要检查的设置的第一个表
  • ProbablyChangedSets (ElemId int16, SetId int, primary key(ElemId, SetId)):第二个表包含要检查PatternSet
  • 的集合

我很好奇这个查询性能还不够吗?

-- sets with intersections
select distinct
   cs.SetId
from ProbablyChangedSets cs
join PatternSet s on
    cs.ElemId = s.ElemId

-- |cs| = setCount * avgSetSize = 10^8 * 10 = 10^9
-- |s|  = avgSetSize = 10
-- numberOfComparisons ~= 10^9 * 10 = 10^10, comparisonComplexity = O(1)

通过足够的并行化,它会非常快 - 只需几秒钟。

或者您的检查是连续的,您需要优化单一检查操作吗?