【问题标题】:Fast keyword lookup快速关键字查找
【发布时间】:2010-12-20 03:10:19
【问题描述】:

我正在编写一个程序,将用户提交的查询与关键字列表进行匹配。该列表大约有 2000 个单词,性能是最重要的。

将此列表存储在 SQL 表或硬编码在 源代码?列表不需要 经常更新。

如果SQL表比较快什么时候数据 类型将是最好的? (诠释, Nvarchar?)

如果硬编码列表更快,什么数据 类型会是最好的? (名单?)

有什么建议吗?

什么是快速查找的最佳内存数据结构?

【问题讨论】:

    标签: c# web-applications


    【解决方案1】:

    存储此数据的位置与性能无关。

    如果您启动您的程序,您将加载字符串数组一次,您从该数据存储中存储它。然后你可以一直使用这个数组,直到你退出程序。

    【讨论】:

    • 这是正确答案。他将数据保存在哪里实际上是无关紧要的。正确的问题是什么是快速查找的最佳内存数据结构?如果对数组进行排序以便可以使用二进制搜索,则该数组很好(所以现在我们是O(log n),其中n 是关键字的数量)。如果这还不够快(在分析之后!)可以考虑尝试。
    • 是的,这是迂腐的......但是,对一组字符串进行二进制搜索真的不是 O(log(N)*log(K)) 其中 N 是单词数,并且K是中位词长?
    • 最坏的情况是O(m log n),其中m 是最大字长,n 是关键字的数量。
    【解决方案2】:

    IMO,如果列表不经常更新,请将其存储在文件(文本/xml)中,然后将其缓存在您的应用程序中,以便下一个请求更快。

    【讨论】:

    【解决方案3】:

    好的,回复您的编辑(基本上将我的评论提升为答案):

    1. 提前指定您期望的性能。

    2. 针对已排序的数组对应用程序进行编码,并使用二进制搜索在数组中搜索关键字。这很容易实现并且提供了不错的性能。然后配置文件以查看它是否符合您要求的性能。如果此性能可以接受,请继续。这里最差的性能是O(m log n),其中n 是关键字的数量,m 是关键字的最大长度。

    3. 如果第二步的性能不可接受,请使用 trie(也称为前缀树)。这里的预期效果是m,其中m 是关键字的最大长度。配置文件以查看这是否符合您的预期性能。如果没有,请重新审视您的绩效标准;他们可能是不合理的。

    4. 1234563 (如果没有冲突,哈希表查找是O(1),而哈希计算函数是O(m),其中m 是关键字的最大长度)。这可能会更快(平均而言),但可能不会那么明显。

    您甚至可以考虑直接跳到最后一步(因为它没有前者那么复杂)。这完全取决于您的需求。例如,尝试的优势在于您可以轻松找出最接近的匹配关键字。

    这里重要的是要有一个你的性能要求的规范和配置文件!使用满足您的性能要求的最简单的实现(为了可维护性、可读性和可实施性(如果不是,现在就是一个词!))

    【讨论】:

    • 感谢您的详细回复。我是 C# 新手,我打算只写一个 reg exp "wordA|wordB|word\sC 这是否足够快,有 2000 个单词?你介意为你提到的方法提供一些示例代码吗?我还在学习。谢谢
    • 不要使用这样的正则表达式。它不是适合这项工作的工具,维护这样的硬编码正则表达式字符串将是一场噩梦。
    【解决方案4】:

    列表不需要经常更新

    我说如果它需要更新,它不属于源代码。

    【讨论】:

    • 可能每月进行一次小改动
    • @program10:Marel K 是对的。特别是如果它是每月一次;这太频繁了,甚至无法远程考虑嵌入到源代码中。
    • 从长远来看,这是大量的源代码维护,并且在部署新版本时完全不必要的停机时间。就像 codymanix 提到的那样 - 只需从 SQL 加载并缓存它 - 这是一个比仅仅为了更新字符串值而修改源代码更具可维护性的选项。
    【解决方案5】:

    硬编码列表更快。检索列表的数据库命中无疑比从内存对象中提取列表要慢。

    至于将值存储在哪种数据类型中,数组可能会比 List 更快并且占用更少的内存,但微不足道。

    【讨论】:

    • 如果在从数据库进行初始检索(启动时)后缓存在本地,则不会。
    • @Jason - 后续点击为真。但是,第一次命中会比较慢。
    • @Kevin Pang:第一击无关紧要。
    • @Jason 很可能,但你不确定。
    【解决方案6】:

    如果列表大部分是静态的,并且您可以花一些时间进行准备(即在应用程序启动时),您最好将关键字列表存储在文本文件中,然后使用 B* 树在内部存储关键字(假设您只关心完全匹配而不关心部分匹配或 Levenshtein 距离)。

    【讨论】:

    • 如果 B*-tree 正在执行动态插入和删除,那么它是好的,但对于静态列表,排序数组就可以了。 B*-tree 的复杂性与排序数组相比没有任何优势。
    • B* 树不一定是正确答案,但我建议在排序数组上使用树结构的原因是搜索速度。搜索一棵树是 O(log N),而搜索一个数组(甚至是排序的数组)是 O(N)。
    • 在哪里可以阅读更多关于部分匹配或 Levenshtein 距离的信息?以后可能需要用到这些
    • @Simon Righarts:您可能需要重新考虑关于搜索排序数组的最后一条语句。
    • @Jason:叹息。我应该把思考作为发帖的先决条件。 (不知何故,我在搜索未排序的数组 - O(N) - 和搜索排序的数组 - 使用二进制搜索的 O(log N) 之间感到困惑)。 @program10:en.wikipedia.org/wiki/Levenshtein_distance(以及底部的另请参阅:链接)应该给你一个合理的开始。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-02-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多