【问题标题】:fast index for "contains string"“包含字符串”的快速索引
【发布时间】:2010-01-18 10:58:28
【问题描述】:

在我的应用程序中,我有多达数百万个短字符串(大部分短于 32 个字符)。我想实现一个带有附加列表的搜索框,该列表仅包含包含在搜索框中输入的整个字符串的元素。我怎样才能预先建立一个索引来快速找到这样的字符串?所有已排序的 STL 容器都会检查整个字符串。

对于输入的搜索字符串“str”,我需要找到所有包含“str”的字符串:“main street”、“struve”、“ustr”等。

【问题讨论】:

    标签: c++ algorithm stl


    【解决方案1】:

    你可以建立一个Permuterm indexes

    对于“struve”,您可以插入Radix tree(或通用搜索树):

    struve$
    truve$s
    ruve$st
    uve$str
    ve$stru
    e$struv
    $struve
    

    要搜索中缀,您将从根节点搜索匹配的前缀字符串。

    【讨论】:

    • 这是一个有趣的解决方案,但它会炸毁一些人使用的数据。
    • 我不认为你会得到比这更好的答案,如果我正确理解这个问题..
    • 如果将所有可搜索文本连接到一个字符串,并且只在树中插入一对指针(每个后缀一个),则可以节省大量内存。如果 n=文本长度,并且 char* 是 4 个字节,那么它是 8n+n+1 对 (n+1)^2 以上。伪代码类似于: content.append("struve$"); tree_insert([[0,7],[1,7],[2,7],[3,7],[4,7],[5,7],[6,7]],record_id);
    【解决方案2】:

    您可以先查看trie's。虽然它们主要用作前缀树,但数据结构本身可能会适应更快的一般搜索。

    【讨论】:

      【解决方案3】:

      如果字符串具有任意长度和任意数量,您可以尝试Aho-Corasick 算法,该算法实现简单,可以在搜索文本长度的O(n) 处缩放,并对所有字符串执行搜索同时。

      或者,如果您要查找的字符串数量很少,请尝试Horspool 算法,该算法非常容易实现,平均每个字符串少于O(n)

      【讨论】:

      • 感谢您的回答,但 Aho-Corasick 不是我想要的:它会在搜索文本中查找完全出现的字典字符串。我需要在字典中找到(某处)找到完整搜索文本的所有条目。
      • 我不太明白。您想在搜索文本中查找所有出现的字符串吗?
      【解决方案4】:

      您说您有数百万个短字符串,所以我假设您无法将其存储在 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 列上创建的索引,因此搜索仍然会很快。

      【讨论】:

      • 我要的是 C++ 中的算法。你的答案是 SQL。
      • RAM 很便宜。为什么不将其保存在 RAM 中?平均 100 万个字符串。长度 32 个字符只有 32MB 或 RAM。在该大小的数据集上使用有效的索引方案可能只会消耗千兆字节。
      【解决方案5】:

      我会使用 SQLite。如果您将所有内容都加载到 RAM 中并需要极高的性能,也许可以使用内存中的数据库。

      【讨论】:

      • SQLite(或其他 SQL DBMS)真的有助于中缀搜索吗?它有特殊的索引吗?
      • FTS 不是中缀搜索!即使在 Lucene 中,中缀搜索也是默认禁用的,因为执行起来成本太高。所以在 SQLite 中使用 FTS 对中缀搜索性能没有帮助。
      • 我有点困惑。我从中缀搜索中了解到,将找到与 /.*my_string.*/ 匹配的每一行。在一般 DBMS 中,搜索“WHERE string = '%my_string%'”是非常无效的。但是,如果您有全文搜索索引,那么它的速度非常快。在 MySQL 的基准测试中(也使用这种匹配语法),在数百万个字符串中搜索需要几毫秒。我没有对 SQLite 进行基准测试,但鉴于它的正常表现,我很有信心。显然,您需要在列上添加 FTS 索引!
      【解决方案6】:

      我可能会从一个倒排索引开始——即一个字母列表,并附加到每个包含该字母的单词列表。如果您只使用字母(特别是如果您将其限制为英语,或者至少是西欧语言),您还可以很容易地为二合字母(即每对字母)、三合字母等创建倒排索引——虽然远超出三元组可能不会获得很多,因为到那时您通常已经将列表缩减到可以很容易地在列表中进行普通字符串搜索的程度。

      请注意,我并不打算将“列表”表示为“链表”,而只是“某种顺序数据结构”,通常表示向量......

      【讨论】:

        猜你喜欢
        • 2018-10-16
        • 2011-03-31
        • 2013-01-20
        • 2013-01-06
        • 2021-08-06
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多