我希望使用布隆过滤器或位掩码来预过滤搜索结果。举一个具体的例子:
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
那么我的问题有两个:
a=1
)? / li>
有关搜索要求的更多详细信息:
description like "%drink%"
(完全内部搜索)或description REGEXP '^|\sdrink'
(“边缘搜索”,在任何单词的开头搜索)。答案 0 :(得分:3)
如果您不能容忍误报,则不能使用布隆过滤器,因为它是一种概率数据结构。
对于位掩码方法而言,显然时间效率不高,该方法以后很难扩展。当您谈论大约800 MB的数据大小时,您正在进入Search or Information Retrieval的范例。现在的问题并不仅限于“ Bitmasks vs Bloom Filters”。只需阅读Search Engine Indexing中与索引相关的概念,它们可能会对您有所帮助。
要解决这些常用词,请阅读stop words是什么以及如何删除它们。要更进一步,如果您不需要找到确切的单词,请阅读有关Stemming和Lemmatization的信息。
这个问题涉及面很广,所以我只提供了一些要阅读的指导。希望您觉得它们有用。
答案 1 :(得分:0)
您的位掩码是简单的布隆过滤器:假设您关心26个可能的字符,即带有m = 26 * rowCount
,k = 1
和以下哈希函数的Bloom filter:hash(firstLetter, rowId) = (firstLetter * rowCount + rowId)
。这很容易实现,但可能效率不高,因为某些字母经常出现(例如字符“ e”)。您的位掩码每行大约需要4个字节,这可能没问题。对于每一行,您都要进行Bloom过滤器查找。
最好使用更复杂的Bloom过滤器。它的外观完全取决于您拥有的数据。假设您使用m = 26 * rowCount
,k = 1
和hash(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 / 8
,k = 1
和hash(firstLetter, secondLetter, rowGroup) = ((11 * firstLetter + 113 * secondLetter) modulo 26) * rowCount / 8 + rowGroup), with
rowGroup = rowId / 8`。因此,您基本上检查了字符对是否出现在某个行组中。这样,即使对于“喜欢”条件和正则表达式,也可以使用Bloom过滤器。