【问题标题】:fastest way to search huge list of big texts搜索大量大文本的最快方法
【发布时间】:2012-02-03 20:59:15
【问题描述】:

我有一个用 C# 编写的 Windows 应用程序,它需要从数据库加载 250,000 行并提供“键入时搜索”功能,这意味着一旦用户在文本框中键入内容,应用程序就需要搜索所有 250,000记录(顺便说一句,单列,每行 1000 个字符)使用like 搜索并显示找到的记录。

我遵循的方法是:

1- 应用程序将所有记录加载到键入的List<EmployeeData>

while (objSQLReader.Read())
{
    lstEmployees.Add(new EmployeesData(
        Convert.ToInt32(objSQLReader.GetString(0)),
        objSQLReader.GetString(1), 
        objSQLReader.GetString(2)));
}

2- 在 TextChanged 事件中,使用 LINQ,我搜索(结合正则表达式)并将 IEnumerable<EmployeesData> 附加到处于虚拟模式的 ListView。

String strPattern = "(?=.*wood*)(?=.*james*)";
    IEnumerable<EmployeesData> lstFoundItems = from objEmployee in lstEmployees
    where Regex.IsMatch(Employee.SearchStr, strPattern, RegexOptions.IgnoreCase)
    select objEmployee;
    lstFoundEmployees = lstFoundItems;

3- 处理RetrieveVirtualItem事件,在ListView中显示item来显示item。

e.Item = new ListViewItem(new String[] { 
    lstFoundEmployees.ElementAt(e.ItemIndex).DateProjectTaskClient, 
    e.ItemIndex.ToString() });

虽然lstEmployees 从 SQL Server 加载列表的加载速度相对较快(1.5 秒),但要在 TextChanged 上进行搜索,使用 LINQ 进行搜索需要 7 分钟以上。通过执行LIKE 搜索直接通过 SQL Server 进行搜索只需不到 7 秒。

我在这里做错了什么?我怎样才能使这个搜索更快(不超过 2 秒)?这是我客户的要求。因此,非常感谢任何帮助。请帮忙...

【问题讨论】:

  • @RamiShareef,我坚持认为这个问题是关于正则表达式的,(实际上比其他任何事情都重要)所以请不要删除正则表达式标签。
  • 你需要它像一个自动完成文本框吗?
  • 是的......就像一个自动完成文本框,但结果应该单独显示在列表框或列表视图中......

标签: c# regex search text


【解决方案1】:

存储文本数据的数据库列是否有索引?如果是这样,类似于 Nicholas 描述的 trie structure 的东西已经在使用中。 SQL Server 中的索引是使用B+ trees 实现的,其平均搜索时间大约为 n 的日志基数 2,其中 n 是树的高度。这意味着,如果您在表中有 250,000 条记录,则搜索所需的操作数是 log base 2 ( 250,000 ) 或大约 18 个操作。

当您将所有信息加载到数据读取器中,然后使用 LINQ 表达式时,它是线性运算 (O) n,其中 n 是列表的长度。所以最坏的情况下,这将是 250,000 次操作。如果您使用 DataView,将会有可用于帮助搜索的索引,这将大大提高性能。

最终,如果不会有太多针对数据库服务器提交的请求,请利用查询优化器来执行此操作。只要不使用字符串前面的通配符执行 LIKE 操作(即LIKE %some_string)(否定使用索引)并且表上有索引,您将获得非常快的性能。如果要提交给数据库服务器的请求太多,要么将所有信息放入 DataView 以便可以使用索引,要么使用上面 Tim 建议的字典,其搜索时间为 O(1 )(按 1 的顺序),假设字典是使用哈希表实现的。

【讨论】:

  • 感谢您的回复。我将不得不在 LIKE 查询中使用 %word%,因为我正在搜索的文本可以位于目标字符串中的任何位置。
  • 如果您在术语前加上通配符,则不会使用索引;仅当通配符在末尾时才有效。但是通常使用名称搜索,尤其是当您谈论一个人的名字时,您可以假设用户会知道前几个字母。我认为在这种情况下,使用您所描述的自动完成控件更可以接受。我不会开始在中间输入一个人的名字吧?
【解决方案2】:

您可能想要预加载内容并为自己构建一个名为 trie 的数据结构

这是内存密集型的,但在这种情况下,这是医生要求的。

【讨论】:

  • 我不知道你是否意识到,但是 OP 有 250.000.000 个字符要搜索,.Net 中的一个对象至少大约 32 个字节。
  • +1 - 这正是我所说的结构类型。
  • @MikeNakis ...首先,我怀疑每条 OP 的 250,000 条记录的长度都不是 1,000 个字符:中值长度很可能要少得多。其次,您可能想阅读尝试。 (试试 Sedgwick 的 算法 (algs4.cs.princeton.edu/home)。还有很多方法可以压缩 trie 表示:搜索 ACM 库可能是值得的。这是一种这样的方法,Tightly打包尝试:如何将大型模型放入内存,并使其加载速度也很快 (aclweb.org/anthology/W/W09/W09-1505.pdf)。
  • 好吧,OP 说“顺便说一句,单列,每行 1000 个字符”。我觉得他说的很清楚。我看了一下链接,看起来很有趣,但也相当复杂。无论如何,我不认为 MSSQL 使用尝试,所以如果 MSSQL 可以在 7 秒内回答一个查询,那么一定有一些可以在内存中完成的事情会比这更快,并且无需尝试。
【解决方案3】:

查看我对this question 的回复。如果您需要即时响应(即与用户键入一样快),将数据加载到内存中可能是一个非常有吸引力的选择。它可能会占用一些内存,但速度非常快。

即使有很多字符(250K 记录 * 1000),有多少个 unique 值?一个基于键的内存结构以及指向与这些键匹配的记录的指针实际上不必那么大,即使考虑到这些键的排列也是如此。

如果数据确实不适合内存或经常更改,请将其保存在数据库中并使用 SQL Server 全文索引,它可以比LIKE 更好地处理此类搜索。这假定从应用程序到数据库的快速连接。

全文索引提供了一组强大的运算符/表达式,可用于使搜索更加智能。它与免费的 SQL 表达式版一起提供,最多可处理 10GB 的数据。

【讨论】:

    【解决方案4】:

    如果可以对记录进行排序,您可能需要进行二分搜索,这对于大型数据集来说要快得多。 .NET 集合中有几种实现,例如 List&lt;T&gt;Array

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2011-04-21
      • 2019-08-24
      • 2016-10-25
      • 2014-03-03
      • 2011-10-28
      • 2023-03-15
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多