首页 > 解决方案 > 搜索文本和缓存数据

问题描述

我有一个包含 150 万行文本的文本文件。

每一行都有不同的句子。

我也有一个单词集。其中大约有2000个。

对于集合中的每个单词,我想提取集合中的所有句子。

它们必须单独发送,因为每个人都将保存到数据库中。

我有一个可行但非常慢的解决方案:

DataContext db = new DataContext();

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

var lines = File.ReadAllLines("collection.csv");
for (var i = 0; i < lines.Length; i += 1)
{
    enWordsPage.Add(lines[i]);
}
enWordsPage = enWordsPage.ConvertAll(d => d.ToLower());

for (int i = 1; i <= 2000; i++)
{
    string enWord = db.GetWordById(i);

    foreach (var item in enWordsPage)
    {
        if (item.Contains(enWord))
        {
            string text = "";
            text = item.Trim();

            int idWord = db.GetIdWordByName(enWord);
            db.AddItemToSentences(idWord, text);
        }
    }
}

每次遍历所有行时,它都会遍历循环。

我可以改进什么来加快速度?

标签: c#performance

解决方案


我认为这是流式传输和复杂性的问题。

在 for 你有一个 foreach 里面,你有 N^2 的复杂度。另外,您要迭代collection.csv两次中的行,一次是填充enWordsPage,第二次是检查一行中的单词是否在数据库中。您可以合并此循环。最后,我将使用 StreamReader 而不是 File.ReadAllLines 来处理读取的行。

我将提出这些更改的原型,但由于我没有您的数据,您必须自己检查它是否有效。

编辑:

你可以试试这段代码,它应该会稍微快一点,因为你不会两次遍历 150 万条记录,但我并没有降低它的复杂性。相反,我已经更改为使用字符串数组,因为遍历它应该比遍历列表更快:

var dbWords = new string[2000];
for (int i = 1; i <= 2000; i++)
{
    dbWords[i] = db.GetWordById(i); //if something else can be used to read these 2000 words from the database, this time can be reduced even more
}

using (StreamReader sr = new StreamReader("collection.csv"))
{
    string line;
    while ((line = sr.ReadLine()) != null)
    {
        for (var index = 0; index < dbWords.Length; index++)
        {
            var dbWord = dbWords[index];
            if (line.Contains(dbWord))
            {
                db.AddItemToSentences(index, line.Trim());
            }
        }
    }
}

我允许自己删除对的调用,db.GetIdWordByName(enWord)因为在您的 for 循环开始时,您使用db.GetWordById(i)的是通过 ID 获取单词,而您的参数是循环的索引。如果我的假设是正确的,这将大大减少从数据库中读取的次数。


推荐阅读