【发布时间】:2010-01-18 10:58:28
【问题描述】:
在我的应用程序中,我有多达数百万个短字符串(大部分短于 32 个字符)。我想实现一个带有附加列表的搜索框,该列表仅包含包含在搜索框中输入的整个字符串的元素。我怎样才能预先建立一个索引来快速找到这样的字符串?所有已排序的 STL 容器都会检查整个字符串。
对于输入的搜索字符串“str”,我需要找到所有包含“str”的字符串:“main street”、“struve”、“ustr”等。
【问题讨论】:
在我的应用程序中,我有多达数百万个短字符串(大部分短于 32 个字符)。我想实现一个带有附加列表的搜索框,该列表仅包含包含在搜索框中输入的整个字符串的元素。我怎样才能预先建立一个索引来快速找到这样的字符串?所有已排序的 STL 容器都会检查整个字符串。
对于输入的搜索字符串“str”,我需要找到所有包含“str”的字符串:“main street”、“struve”、“ustr”等。
【问题讨论】:
你可以建立一个Permuterm indexes。
对于“struve”,您可以插入Radix tree(或通用搜索树):
struve$
truve$s
ruve$st
uve$str
ve$stru
e$struv
$struve
要搜索中缀,您将从根节点搜索匹配的前缀字符串。
【讨论】:
您可以先查看trie's。虽然它们主要用作前缀树,但数据结构本身可能会适应更快的一般搜索。
【讨论】:
如果字符串具有任意长度和任意数量,您可以尝试Aho-Corasick 算法,该算法实现简单,可以在搜索文本长度的O(n) 处缩放,并对所有字符串执行搜索同时。
或者,如果您要查找的字符串数量很少,请尝试Horspool 算法,该算法非常容易实现,平均每个字符串少于O(n)。
【讨论】:
您说您有数百万个短字符串,所以我假设您无法将其存储在 RAM 中并将其保存在数据库中。 假设您将“短字符串”保存在名为 my_string (id, string) 的表中。 创建另一个表,我们将其命名为 my_substring (id, substring[unique]),其中包含 my_string 中每个字符串的每个子字符串。 还要为上面的两个表创建一个连接表:my_substring_to_string(id, substring_id, string_id),我想它的内容是显而易见的。
现在搜索简单快捷:在 my_substring 中搜索您的子字符串(记得在 my_substring.substring 上创建索引)并通过 my_substring_to_string 将其与 my_string 连接。
添加和删除新的短字符串需要更新 my_substring 和 my_substring_to_string,但这些都非常简单。
如果此解决方案会生成大小不可接受的 my_substring 表,则可以对其进行优化。不要保留每个子字符串,而是尝试保留每个后缀并使用 ilike 搜索“子字符串%”。 例如,如果单词是“blues”,则必须存储后缀: 'blues'、'lues'、'ues'、'es'、's'(与 'blues' 连接)。然后搜索 'lu' (ilike 'lu%') 将匹配 'lues'。这样,数据库仍然可以使用在 my_substring.substring 列上创建的索引,因此搜索仍然会很快。
【讨论】:
我会使用 SQLite。如果您将所有内容都加载到 RAM 中并需要极高的性能,也许可以使用内存中的数据库。
【讨论】:
我可能会从一个倒排索引开始——即一个字母列表,并附加到每个包含该字母的单词列表。如果您只使用字母(特别是如果您将其限制为英语,或者至少是西欧语言),您还可以很容易地为二合字母(即每对字母)、三合字母等创建倒排索引——虽然远超出三元组可能不会获得很多,因为到那时您通常已经将列表缩减到可以很容易地在列表中进行普通字符串搜索的程度。
请注意,我并不打算将“列表”表示为“链表”,而只是“某种顺序数据结构”,通常表示向量......
【讨论】: