位掩码与布隆过滤器

时间:2019-08-27 04:32:15

标签: algorithm search optimization bitmask bloom-filter

我希望使用布隆过滤器或位掩码来预过滤搜索结果。举一个具体的例子:

id,product,description
1,"coke", "A popular soft drink since 1900"
2,"pepsi", "A popular soda, similar to coke"
3,"soda", "A word to describe various soft drinks"

如果用户搜索单词“可乐”,我们将在product="coke"上匹配第1行和description(has word)="coke"

我们有内存限制,因此不能索引太多项目,但是我正在考虑根据每行包含的第一个字母实现位掩码。这样,我们可以看到c包含在第1行和第2行中,而不包含在第3行中,因此我们根本不会在搜索中包含它。

如果我们采用了前三行,则“ word-starts-with”掩码看起来像(对于字母表的前三个字母)-

a  b  c  d
1  0  1  1 (row 1 -- coke)  -- has c? Y
1  0  1  0 (row 2 -- pepsi) -- has c? Y
1  0  0  1 (row 3 -- soda)  -- has c? NO -- SKIP

那么我的问题有两个:

  • 对于上述情况,在位掩码上使用Bloom过滤器有什么好处吗?为什么或者为什么不? (我不太了解Bloom筛选器,也从未使用过它。)
  • 上面的一个字母的位掩码看起来像是有用的,还是看起来不能真正解决任何问题(例如,每一行可以有a=1)? / li>
  • 是否存在解决常见字母/单词的建议方法。例如,“ / a”,“ the”等似乎都将出现在几乎所有带有自然文本的列中。

有关搜索要求的更多详细信息:

  • 最大数据大小为1GB。根据行的大小,这将转换为1M-10M行之间的任何位置。
  • 几乎没有可用的额外空间,因此像传统索引这样的东西就不成问题了。作为参考,我们假设任何数据集上都有10%的净空来存储辅助信息,例如bitmask / filter / index / etc。
  • 两个示例查询将是description like "%drink%"(完全内部搜索)或description REGEXP '^|\sdrink'(“边缘搜索”,在任何单词的开头搜索)。

2 个答案:

答案 0 :(得分:3)

如果您不能容忍误报,则不能使用布隆过滤器,因为它是一种概率数据结构。

对于位掩码方法而言,显然时间效率不高,该方法以后很难扩展。当您谈论大约800 MB的数据大小时,您正在进入Search or Information Retrieval的范例。现在的问题并不仅限于“ Bitmasks vs Bloom Filters”。只需阅读Search Engine Indexing中与索引相关的概念,它们可能会对您有所帮助。

要解决这些常用词,请阅读stop words是什么以及如何删除它们。要更进一步,如果您不需要找到确切的单词,请阅读有关StemmingLemmatization的信息。

这个问题涉及面很广,所以我只提供了一些要阅读的指导。希望您觉得它们有用。

答案 1 :(得分:0)

您的位掩码是简单的布隆过滤器:假设您关心26个可能的字符,即带有m = 26 * rowCountk = 1和以下哈希函数的Bloom filterhash(firstLetter, rowId) = (firstLetter * rowCount + rowId) 。这很容易实现,但可能效率不高,因为某些字母经常出现(例如字符“ e”)。您的位掩码每行大约需要4个字节,这可能没问题。对于每一行,您都要进行Bloom过滤器查找。

最好使用更复杂的Bloom过滤器。它的外观完全取决于您拥有的数据。假设您使用m = 26 * rowCountk = 1hash(firstLetter, secondLetter, rowId) = ((11 * firstLetter + 113 * secondLetter) modulo 26) * rowCount + rowId)。这样,它使用相同的空间,但位分配得更均匀。对于频繁的字母,这会大大加快搜索速度,但代价是搜索频率较低的字母会稍微慢一些。

更好的方法可能是合并多行,假设每行合并8行(行0..7、8..15等),然后设置Bloom过滤器中所有需要的位。这样,您可以大大减少查找次数。

如果查询的格式可以为like "%drink%",则仅查看前几个字符的过滤器将无用:您仍然必须进行全面扫描。取而代之的是,您可以使用布隆过滤器,该过滤器组合(说)8行,并设置每个字符对的所有位。也就是说,['dr', 'ri', 'in', 'nk'],并使用m = 26 * rowCount / 8k = 1hash(firstLetter, secondLetter, rowGroup) = ((11 * firstLetter + 113 * secondLetter) modulo 26) * rowCount / 8 + rowGroup), with rowGroup = rowId / 8`。因此,您基本上检查了字符对是否出现在某个行组中。这样,即使对于“喜欢”条件和正则表达式,也可以使用Bloom过滤器。