【问题标题】:Find keyword fastest algorithm in C#在 C# 中查找关键字最快的算法
【发布时间】:2013-09-16 14:22:21
【问题描述】:

您好,我正在尝试创建一个非常快速的算法来检测集合中的关键字或关键字列表。

在任何事情之前,我已经阅读了很多 stackoverflow(和其他)帖子,但无法将性能提高到我期望的水平。

我当前的解决方案能够在 0.1825 毫秒内分析 200 个字符的 输入 和 400 个列表的集合(在 1 毫秒内分析 5 个输入),但这太长了,我希望将此性能至少提高 5 倍(这是我的要求)。

解决方案测试:

  • 手动研究
  • 高度复杂的正则表达式(组、反向引用...)
  • 多次调用简单的正则表达式(以匹配每个关键字)
  • 简单的正则表达式匹配输入关键字,然后与跟踪的关键字相交(当前解决方案)
  • 多线程(对性能的巨大影响 (*100),所以我不确定这是否是解决此问题的最佳解决方案)

目前的解决方案:

input (string) : 解析并分析其中包含的关键字列表的字符串。 示例:“你好,世界!#piloupe 先生你好吗?”。

tracks (string[]) : 我们要匹配的字符串数组(空格表示 AND)。示例:“hello world”匹配一个同时包含 'hello' 和 'world' 的字符串,无论它们的位置是什么

keywordList (string[][]) : 输入匹配的字符串列表。 示例:{ { "hello" }, { "#piloupe" }, { "hello", "world" } }

uniqueKeywords (string[]) : 表示keywordList的所有唯一关键字的字符串数组。使用前面的关键字列表:{ "hello", "#piloupe", "world" }

所有这些先前的信息不需要进行任何性能改进,因为它们只针对任何输入构建一次。

查找轨迹算法:

// Store in the class performing the queries
readonly Regex _regexToGetAllInputWords = new Regex(@"\#\w+|\w+", RegexOptions.Compiled);

List<string> GetInputMatches(input)
{
    // Extract all the words from the input
    var inputWordsMatchCollection = _regexToGetAllInputWords.Matches(input.ToLower()).OfType<Match>().Select(x => x.Value).ToArray();

    // Get all the words from the input matching the tracked keywords
    var matchingKeywords = uniqueKeywords.Intersect(inputWordsMatchCollection).ToArray();

    List<string> result = new List<string>();

    // For all the tracks check whether they match
    for (int i = 0; i < tracksKeywords.Length; ++i)
    {
        bool trackIsMatching = true;

        // For all the keywords of the track check whether they exist
        for (int j = 0; j < tracksKeywords[i].Length && trackIsMatching; ++j)
        {
            trackIsMatching = matchingKeywords.Contains(tracksKeywords[i][j]);
        }

        if (trackIsMatching)
        {
            string keyword = tracks[i];
            result.Add(keyword);
        }
    }

    return result;
}

任何帮助将不胜感激。

【问题讨论】:

  • 你如何测试性能?
  • 看一眼您的代码,似乎使用 Parallel LINQ 可以加快多核系统的速度。
  • 你有没有打破这个时间?我很想知道List&lt;string&gt; result = new List&lt;string&gt;(); 之前还是之后需要更长时间。
  • 你如何测试性能:我在调用方法之前启动秒表并在调用之后停止它。

标签: c# regex performance parsing


【解决方案1】:

简短的回答是解析每个单词,并将其存储到类似二叉树的集合中。 SortedList 或 SortedDictionary 将成为您的朋友。

只需很少的代码,您就可以将单词添加到 SortedList,然后对该 SortedList 执行 .BinarySearch()。这是一个 O(log n) 实现,您应该能够在几次迭代中搜索数千或数百万个单词。使用 SortedList 时,性能问题将出现在对 SortedList 的插入上(因为它会在插入时排序)。但这是进行二分搜索所必需的。

我不会打扰线程,因为您需要不到 1 毫秒的结果。

长答案是查看类似 Lucene 的东西,如果您正在执行自动完成式搜索,这可能会特别有用。 RavenDB 在后台使用 Lucene,可以为您做后台索引,它会在几毫秒内搜索数百万条记录。

【讨论】:

    【解决方案2】:

    我想建议使用hash table。 使用散列,您可以将字符串文本转换为表示该字符串在散列表中的索引的整数。 它比顺序搜索快得多。

    【讨论】:

    • 您好 :) 请您更具体一些,因为我已经尝试过使用 HashSet 的解决方案。
    • hi bud :) 这个话题之前讨论过,请看这里:stackoverflow.com/questions/114085/… 告诉我是否有帮助:)
    【解决方案3】:

    最终的解决方案是Elastic binary tree 数据结构。在HAProxy 中使用它来匹配代理 HTTP 请求中的 URL 规则(也用于许多其他目的)。
    ebtree 是根据您的“关键字”模式构建的数据结构,这允许比 SortedList 或散列更快的匹配。比散列更快是可能的,因为散列读取输入字符串一次(或至少几个字符)以生成散列码,然后再次评估.Equals()。因此散列读取输入的所有字符 1 次以上。 ebtree 最多读取所有字符一次并找到匹配项,或者如果没有匹配项,则在 O(log(n)) 个字符之后告诉它 n em> 是模式的数量。
    我不知道 ebtree 的现有 C# 实现,但如果有人愿意,肯定很多人会很高兴。

    【讨论】:

      猜你喜欢
      • 2016-02-11
      • 2019-06-26
      • 1970-01-01
      • 2012-06-15
      • 2010-12-20
      • 1970-01-01
      • 2013-03-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多