在 C# 中查找关键字最快算法

本文关键字:算法 关键字 查找 | 更新日期: 2023-09-27 18:31:32

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

在此之前,我已经阅读了很多堆栈溢出(和其他)帖子,但无法将性能提高到我预期的水平。

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

经测试的解决方案:

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

当前解决方案:

输入(字符串):要解析和分析的字符串,以验证其中包含的关键字列表。示例:"你好世界!#piloupe 先生,你好吗?

曲目(string[]):我们要匹配的字符串数组(空格表示 AND)。示例:"hello world"匹配包含"hello"和"world"的字符串,无论它们的位置如何

关键字列表 (字符串[][]) :要从输入匹配的字符串列表。示例 : { {

"hello" }, { "#piloupe" }, { "hello", "world" } }

uniqueKeywords (string[]) :表示关键字列表的所有唯一关键字的字符串数组。使用前面的关键字列表,这将是:{"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;
}

任何帮助将不胜感激。

在 C# 中查找关键字最快算法

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

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

我不会打扰线程,因为您需要在不到 1 毫秒的时间内获得结果。

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

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

最终的解决方案是弹性二叉树数据结构。它在HAProxy中用于将规则与代理HTTP请求中的URL匹配(以及许多其他目的)。
ebtree是从你的"关键字"模式构建的数据结构,它允许比SortedList或哈希更快的匹配。比哈希更快是可能的,因为哈希读取输入字符串一次(或至少几个字符)以生成哈希代码,然后再次计算.Equals()。因此,散列读取输入的所有字符 1+ 次。ebtree 最多读取所有字符一次并找到匹配项,或者如果没有匹配项,则在 O(log(n)) 字符之后告诉它,其中 n 是模式的数量。
我不知道 ebtree 的现有 C# 实现,但如果有人接受它,肯定会有很多人会很高兴。